codedge-llc / pigeon Goto Github PK
View Code? Open in Web Editor NEWiOS and Android push notifications for Elixir
Home Page: https://hex.pm/packages/pigeon
License: MIT License
iOS and Android push notifications for Elixir
Home Page: https://hex.pm/packages/pigeon
License: MIT License
Using the example in the Pigeon README we found that GCM was not showing the notification. It took a while to figure out that the app had to be open.
If the notification contains an alert in a data element it does show the notification on the Nexus device we're testing with.
"data":{"alert":"your alert"}
@hpopp I've replaced chatterbox with ninenines/gun successfully and was wondering if you'd want to merge that kind of change? I'm planning on doing the same with httpoison to keep the list of dependencies simple.
Seeing this error occasionally when pushing large batches to APNS:
2017-08-02T22:15:24.618 [error] [email protected] missing_topic: The apns-topic header of the request was not specified and was required. The apns-topic
header is mandatory when the client is connected using a certificate that supports
multiple topics.
%Pigeon.APNS.Notification{device_token: "xxxxxxxx", expiration: nil, id: nil, payload: %{"aps" => %{"alert" => %{"body" => "xxxxxx.", "title" => xxxxxx"}, "badge" => 1, "sound" => "default"}, "data" => %{"guid" => "xxxxx", "message_id" => "xxxxxx", "url" => "xxxxxxxxx"}}, topic: "topic.name.here"}
(where all actual data has been replaced by dummy data).
This is strange because it seems like the code should auto set the topic. Could it be because I am sending a large # of notifications at once? Note that this only happened after upgrading to Pigeon 1.0 from 0.13.
I am getting this error when trying to send messages from a task that was scheduled with quantum (https://github.com/c-rack/quantum-elixir)
2016-09-01T07:30:00.443676253Z app[web.1]: 07:30:00.443 [error] GenServer :apns_worker terminating
2016-09-01T07:30:00.443742038Z app[web.1]: ** (stop) exited in: :gen_fsm.sync_send_all_state_event(#PID<0.246.0>, {:new_stream, #PID<0.245.0>})
2016-09-01T07:30:00.443768527Z app[web.1]: ** (EXIT) no process
2016-09-01T07:30:00.443778382Z app[web.1]: (stdlib) gen_fsm.erl:249: :gen_fsm.sync_send_all_state_event/2
2016-09-01T07:30:00.443814673Z app[web.1]: src/h2_client.erl:128: :h2_client.send_request/3
2016-09-01T07:30:00.443826612Z app[web.1]: (pigeon) lib/pigeon/apns_worker.ex:102: Pigeon.APNSWorker.send_push/3
2016-09-01T07:30:00.443835772Z app[web.1]: (stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
2016-09-01T07:30:00.443841878Z app[web.1]: (stdlib) gen_server.erl:667: :gen_server.handle_msg/5
2016-09-01T07:30:00.443848000Z app[web.1]: (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Any ideas?
https://firebase.google.com/docs/cloud-messaging/
I'm not sure if there is a difference from the server -- maybe just a matter of documentation?
17:05:51.191 [error] GenServer #PID<0.240.0> terminating
** (ArgumentError) argument error
:erlang.byte_size(3420729)
(kadabra) lib/hpack/table.ex:108: Kadabra.Hpack.Table.entry_size/1
(kadabra) lib/hpack/table.ex:82: Kadabra.Hpack.Table.add_header/2
(kadabra) lib/hpack.ex:67: Kadabra.Hpack.literal_header_inc_indexing/2
(kadabra) lib/hpack.ex:17: Kadabra.Hpack.do_decode_headers/3
(kadabra) lib/connection.ex:146: Kadabra.Connection.do_recv_headers/2
(kadabra) lib/connection.ex:80: Kadabra.Connection.handle_cast/2
(stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
It's obviously kadabra issue but i'm posting it here because it's easly reproducible using pigeon.
To reproduce this. Send 599 notifcations using same APNSWorker (my topic length is 20, don't know if makes any difference). Try sending another one.
There is a new problem appeared today after I have updated deps. Google says possibly it's tls version error. Any idea how to fix it?
** (Mix) Could not start application pigeon: Pigeon.start(:normal, []) returned an error: shutdown: failed to start child: :default
** (EXIT) bad return value: {:error, {:tls_alert, 'handshake failure'}}
just deployed an app using the new FCM workers to production and I'm seeing the following errors come through quite a bit. looks like the response isn't valid json according to Poison...
** (Poison.SyntaxError) Unexpected token at position 143: {
(poison) lib/poison/parser.ex:57: Poison.Parser.parse!/2
(poison) lib/poison.ex:83: Poison.decode!/2
(pigeon) lib/pigeon/fcm/worker.ex:193: Pigeon.FCM.Worker.process_end_stream/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:end_stream, %Kadabra.Stream.Response{body: "{\"multicast_id\":5100906380876488637,\"success\":1,\"failure\":0,\"canonical_ids\":0,\"results\":[{\"message_id\":\"0:1501697155598441%2e36f6e02e36f6e0\"}]}{\"multicast_id\":5670313992973191076,\"success\":1,\"failure\":0,\"canonical_ids\":0,\"results\":[{\"message_id\":\"0:1501697155958054%2e36f6e02e36f6e0\"}]}", headers: [{":status", "200"}, {"content-type", "application/json; charset=UTF-8"}, {"date", "Wed, 02 Aug 2017 18:05:55 GMT"}, {"expires", "Wed, 02 Aug 2017 18:05:55 GMT"}, {"cache-control", "private, max-age=0"}, {"x-content-type-options", "nosniff"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"server", "GSE"}, {"alt-svc", "quic=\":443\"; ma=2592000; v=\"39,38,37,36,35\""}, {"accept-ranges", "none"}, {"vary", "Accept-Encoding"}, {":status", "200"}, {"content-type", "application/json; charset=UTF-8"}, {"date", "Wed, 02 Aug 2017 18:05:55 GMT"}, {"expires", "Wed, 02 Aug 2017 18:05:55 GMT"}, {"cache-control", "private, max-age=0"}, {"x-content-type-options", "nosniff"}, {"x-frame-options", "SAMEORIGIN"}, {"x-xss-protection", "1; mode=block"}, {"server", "GSE"}, {"alt-svc", "quic=\":443\"; ma=2592000; v=\"39,38,37,36,35\""}, {"accept-ranges", "none"}, {"vary", "Accept-Encoding"}], id: 1, status: 200}}
I have implemented a periodic ping to keep the connection alive: https://github.com/arkadiyk/pigeon/commit/83919469d8b9be4753143e493c039d5a78077ccd
Does it make sense to solve the problem this way? If it does I can make the timeout configurable and make a PR..
apns4erl
solved this problem in different way: inaka/apns4erl#54
I am running pigeon 0.9.0, and occasionally see the following error message. When this happens, the push notification fails to send. It appears as though the process is restarted correctly, and the next time, the notification is sent correctly.
/var/log/galdr/system.log prod-us-galdr-20 13:51:57.577 [error] GenServer :apns_worker terminating
/var/log/galdr/system.log prod-us-galdr-20 ** (stop) exited in: :gen_fsm.sync_send_all_state_event(#PID<0.24316.21>, {:new_stream, #PID<0.24310.21>})
** (EXIT) no process
(stdlib) gen_fsm.erl:249: :gen_fsm.sync_send_all_state_event/2
(chatterbox) src/h2_client.erl:128: :h2_client.send_request/3
(pigeon) lib/pigeon/apns_worker.ex:108: Pigeon.APNSWorker.send_push/3
(stdlib) gen_server.erl:615: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:681: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
I think the documentation should be changed from:
config :pigeon,
apns_mode: :dev,
apns_cert: "cert.pem",
apns_key: "key_unencrypted.pem"
apns_2197: true (optional)
To
config :pigeon,
apns_mode: :dev,
apns_certfile: "cert.pem",
apns_keyfile: "key_unencrypted.pem"
apns_2197: true (optional)
Because we can manage response manually with on_response
we need option to disable noise logs which pigeon output internally
pigeon/lib/pigeon/apns_worker.ex
Line 283 in 5cad838
README needs to be broken into separate guides for GCM and APNS before v1.0
. Individual functions should be properly documented as well.
which is JWT per organization instead of per app certificate?
I'm discovering that i'm having flaky success using the push worker to deliver messages. The Pigeon.APNS.push
method returns :ok
, but my callback never gets fired. What's the easiest way to diagnose what is happening? Could the HTTP/2 connection be timing out?
Can't find a way to send options parameters from https://developers.google.com/cloud-messaging/http-server-ref#downstream-http-messages-json to gcm. Tried adding to notification and data but they don't work there. Also tried adding them to notification payload directly but am getting key does not exist error.
Am I missing something here?
Thanks
Apple introduce for iOS 8.0 push notification with action in background in VoIP.
I would like to know if the lib pigeon in compatible with this feature. You can see below a Git with a full explication of the backend (C#) and iOS app.
Thanks
Hello, since FCM has replaced GCM, I was wondering if this library supports FCM?
This is intended to start a conversation about changes need to handle multiple environments or multiple topics.
With coming changes to APNS I suspect it will be more common to deliver notifications to several topics in the same application. For example pushing to both production and sandbox or pushing to two separate topics.
Currently the certificate to use is specified in the config but it should be possible to specify a push topic and load a map between certificates and topics instead
%{ "com.exmaple.topic1":"/path/to/cert1.p12", "com.exmaple.topic2":"/path/to/cert2.p12"}
and the add the option to push against a Topic. At some point Apple will move over to JWT which should simplify this dramatically.
This probably requires a separate pool per topic.
in APNS (Apple iOS) documentation there is an error in the section Custom Worker Connection, as it states to use to:
instead of name:
as the option parameter for Pigeon.APNS.push/2
Instead of:
Send pushes with a
to
option in your second parameter.n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic")
Pigeon.APNS.push(n, to: :custom_worker)
should be:
Send pushes with a
name
option in your second parameter.n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic")
Pigeon.APNS.push(n, name: :custom_worker)
Seems like kadabra is sending :closed messages to the APNS worker (which theoretically shouldn't be happening with the ping...), and the APNS worker can't handle them. For now I've custom forked this to basically just shutdown (and thus auto-restart) the worker when this happens. Are there any drawbacks to doing this? Will I lose messages?
config :pigeon,
apns_mode: :dev,
apns_cert: "cert.pem",
apns_key: "key_unencrypted.pem"
apns_2197: true (optional)
Am I supposed to copy the entire content of the key / certificate into the config or does this actually refer a file?
If a file, where is the file supposed to be for pigeon to find it?
Hello , i uninstalled the app and then try to send message throught pigeon, and in callback, it is giving {:ok,notification}. how is this possible. ?
Currently, pigeon does not handle HTTPoison.Error
when doing request to GCM (https://github.com/codedge-llc/pigeon/blob/master/lib/pigeon/gcm.ex#L52). This causes the process to crash if GCM is closing connection. After the max restart limit is reached, pigeon is causing the entire node to crash.
A fragment of the crash report:
crasher:
initial call: Elixir.Pigeon.GCM:-do_push/3-fun-2-/0
pid: <0.1388.3>
registered_name: []
exception exit: {{badmatch,
{error,
#{'__exception__' => true,
'__struct__' => 'Elixir.HTTPoison.Error',
id => nil,
reason => closed}}},
[{'Elixir.Pigeon.GCM','-do_push/3-fun-1-',4,
[{file,"lib/pigeon/gcm.ex"},{line,52}]},
{'Elixir.Task.Supervised',do_apply,2,
[{file,"lib/task/supervised.ex"},{line,85}]},
{'Elixir.Task.Supervised',reply,5,
[{file,"lib/task/supervised.ex"},{line,36}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,240}]}]}
in function 'Elixir.Task.Supervised':exit/4 (lib/task/supervised.ex, line 116)
in call from 'Elixir.Task.Supervised':reply/5 (lib/task/supervised.ex, line 36)
I'm happy to help with the issue, but I'd appreciate any guidance on that. I'm not sure what's the best way to handle this error. I guess doing the request in the case
statement and pattern matching on success and error would help, but maybe you can provide some feedback.
Or will be resolved by #52 ?
Can I use FCM with CCS/XMPP using pigeon?
Right now it catches the response data but does nothing with it.
Hi there,
We are attempting to use the pigeon
lib for VOIP push notification and consistently get a timeout error with Pigeon.
We have confirmed the certs are valid, it work from the dev environment.
We have also confirmed the device tokens are valid, for the reason above.
The request in code looks like this
Pigeon.APNS.Notification.new("Incoming call...", deviceToken, "com.company.APP")
|> put_sound("default")
|> put_alert(%{"title" => "Incoming call..."})
|> Pigeon.APNS.push
And the timeout response is ...
{:error, :timeout,
%Pigeon.APNS.Notification{device_token: "218b6d43ea916968939ca5eaab2eb6eaf6f730358fcd2ce8365ec88825a0b519",
expiration: nil, id: nil,
payload: %{"SIN" => "AwECAd1ozbA5QSSM7TXqMtyCiDtkE1kDNDU4AQ==",
"aps" => %{"alert" => %{"title" => "Incoming call..."},
"sound" => "default"}},
topic: "com.company.APP"}}
and our config looks like this config/config.exs
config :pigeon,
apns_mode: :dev,
apns_cert: "certs/new/cert.pem",
apns_key: "certs/new/key_unencrypted.pem",
apns_2197: false
the certs are in a directory relative to priv/
And we have checked telnet gateway.push.apple.com 2195 && telnet gateway.push.apple.com 2196
connect without an issue
Any ideas on how to proceed or further debug this would be very helpful, specifically I cannot tell if there is a problem with the configuration and usage of pigeon
as described above?
Thanks
I have a GenServer running that sends out push notifications using pigeon. I have recently updated to 0.10.3 and I started seeing the following messages every time I sent a GCM push notification:
22:51:05.504 [warn] Reverb.Backend.Pusher Reverb.Backend.Pusher received unexpected message in handle_info/2: {#Reference<0.0.3.2852>, [nil]}
22:51:05.504 [warn] Reverb.Backend.Pusher Reverb.Backend.Pusher received unexpected message in handle_info/2: {:DOWN, #Reference<0.0.3.2852>, :process, #PID<0.2565.0>, :normal}
After tracking this down, it appears that on line 59 of gcm.ex, you are calling Task.async
but never calling Task.await
.
When the Task finishes, this causes the DOWN message to be sent to the parent, which is my GenServer. According to the elixir documentation, you should always be calling Task.await for every Task.async
hello, when i tried doing multiple gcm requests with
Pigeon.GCM.Notification.new([android_tokens], msg)
it threw below error.
10:55:30.291 [error] Task #PID<0.425.0> started from #PID<0.424.0> terminating ** (ArgumentError) argument error :erlang.binary_to_existing_atom("not_registered", :utf8) (pigeon) lib/pigeon/gcm.ex:134: Pigeon.GCM.parse_result/1 (pigeon) lib/pigeon/gcm.ex:111: Pigeon.GCM.process_callback/3 (pigeon) lib/pigeon/gcm.ex:107: anonymous fn/4 in Pigeon.GCM.handle_200_status/3 (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3 (pigeon) lib/pigeon/gcm.ex:107: Pigeon.GCM.handle_200_status/3 (elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2 (elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5 Function: #Function<6.133904638/0 in Pigeon.GCM.do_push/3> Args: []
Will need to implement some sort of tracking to know which notifications have been sent. In some of my initial testing I found the :ssl_closed
message arrives too late for some messages sent after an invalid device token.
Currently, Pigeon.GCM.Notification only has a data field. Please provide ability to pass in a notification payload according to GCM reference
I see the discussion on #6 on how Pigeon is configured to look for the cert at a path relative to the root. For purposes of keeping various sensitive keys secret, I'm used to keeping them in the environment variables and out of source control. Is there a way to do this with APNS's certificate files? I'm using Heroku.
Thanks!
Seeing this issue on the new FCM update:
Got GOAWAY, PROTOCOL_ERROR, Last Stream: 47, Rest: invalid_new_stream_id
.
Any ideas?
Opening this for a general discussion on tasks remaining for v1.0
release.
Task list so far...
I'm not sure yet what kind of API ADM pushing would look like. Despite being Android, its implementation looks a lot more like APNS.
({application_start_failure,pigeon,{{shutdown,{failed_to_start_child,apns_worker,{tls_alert,"certificate unknown"}}},{'Elixir.Pigeon',start,[normal,[]]}
Link to the old docs is broken. Making a note to link the new one and make sure the error response keys and descriptions still match.
Trying to set up Push in our app using the functionality outlined here:
Is it possible to use Pigeon with Json web tokens?
It would be nice to be able to use something like Bypass in my own tests, so as to avoid sending push notifications from CI or configuring CI with all the certificates in credentials -- I'm of course relying on Pigeon itself already having those tests.
I'm not sure if something like that could replace out APNS in particular, being that is uses Chatterbox. What kind of configuration would be needed to do something like that in tests?
From table 9 in FCM manual:
The server couldn't process the request in time. Retry the same request, but you must:
- Honor the Retry-After header if it is included in the response from the FCM Connection Server.
- Implement exponential back-off in your retry mechanism. (e.g. if you waited one second before the first retry, wait at least two second before the next one, then 4 seconds and so on). If you're sending multiple messages, delay each one independently by an additional random amount to avoid issuing a new request for all messages at the same time.
Either implement the two options directly in the worker or update GCM.NotificationResponse
to help consumer make informed decisions.
HTTP/2 supports multiple streams, but it seems like Pigeon currently waits for a response before sending another notification. When timing a push of 1,000 notifications it seemed to be taking > 100ms per notification.
By not waiting for the response before the next push, Pigeon could be sending 20+ notifications concurrently, cutting the time down dramatically.
The number of streams is dynamic, so there is no optimal number of concurrent notifications to send (unfortunately).
The APNs server allows multiple concurrent streams for each connection. The exact number of streams is based on server load, so do not assume a specific number of streams. https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html
Would you recommend using Pigeon.XXX.start_connection in order to dynamically load the certs/keys instead of hard coding them into the config? A worker would be started before a batch push and then finished upon response so that we can guarantee it's not lingering when not needed.
Thoughts?
Is there any way to configure pidgeon to read configuration from the system at runtime?
something like the following. similar to how phoenix runtime configuration is setup.
config :pigeon, :apns,
default: %{
cert: {:system, "APNS_CERTIFICATE"},
key: {:system, "APNS_KEY"},
mode: :dev
}
Sorry to open this issue again, but I got the same error when I try to start a second time the server.
here my conf:
config :pigeon,
apns_mode: :dev,
apns_cert: {:panda_phoenix, "cert/cert.pem"},
apns_key: {:panda_phoenix, "cert/key.pem"},
apns_2197: true
def application do
[...
applications:[..., :pigeon]]
end
defp deps do
[...
{:pigeon, "~> 0.9.0"},
{:chatterbox, "~> 0.3.0-15-g401cef6", github: "joedevivo/chatterbox"},
...]
end
I did not succeed to user "0.3.0"
Steps:
1 - mix deps.clean --all
2 - mix deps.get
3 - mix phoenix.server
"Ok the server work perfectly and I can send push on iOS"
4 - control c
to kill the server
5 - mix phoenix.server
I got the error below
** (Mix) Could not start application pigeon: Pigeon.start(:normal, []) returned an error: shutdown: failed to start child: :apns_worker
** (EXIT) an exception was raised:
** (MatchError) no match of right hand side value: {:error, :eaddrinuse}
src/h2_connection.erl:148: :h2_connection.init/1
(stdlib) gen_fsm.erl:325: :gen_fsm.init_it/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
@hpopp, the flag have set to true and the same issue
@nathany, when I run ps aux | grep phoenix
, After kill my phoenix server I still have a service phoenix running, I guess:
55315 ?? 0:01.96 /usr/local/Cellar/erlang/19.0.2/lib/erlang/erts-8.0.2/bin/beam.smp -- -root /usr/local/Cellar/erlang/19.0.2/lib/erlang -progname erl -- -home ......... /Users/douvi/Documents/my_app .......
I found a solution I need to kill my service erlang to start again my server...
kill -9 55315
I understand that there are an atom option, :dev
or :prod
, for the APNS mode
configuration setting. It would be great if instead we could pass some environment variable System.get_env("APNS_MODE") .
I have my staging and production on Heroku and I need to manually change my configuration from :dev to :prod every time I push a new release :(
Thanks!
I have a challenge that I'm not sure how to address with the current callback-based API for handling responses.
It works well enough for deleting bad device tokens / registration ids from the database, but I'm not sure how to collect the responses to return a success or failure.
Right now I have a web API that will send notifications to one-or-more devices for a single user. I'd like to be able to launch all the notifications (Android or iOS) for that user, then collect all the responses, and decide what to return back to the API.
Any thoughts on how to accomplish this?
On dev environment, I sometimes get the following timeout
[error] GenServer :apns_worker terminating
** (MatchError) no match of right hand side value: {:error, "timeout."}
(pigeon) lib/pigeon/apns_worker.ex:74: Pigeon.APNSWorker.send_push/3
(pigeon) lib/pigeon/apns_worker.ex:54: Pigeon.APNSWorker.handle_cast/2
Is there an exponential backoff retry mechanism on Pigeon planned? Or is there at least a way to find out the push failed from the API?
Is there a way to run multiple instances of the same APNS worker (for example, using poolboy)? Would be helpful to be able to open up multiple connections for the same key/cert and parallelize notification sending in that regard.
When using the FCM workers, I see a decent number of the GOT GOAWAY, NO_ERROR
logs (which it seems like the worker code is aware of). Just wondering what the cause of this is and if there's a way I can mitigate it?
Hello, I wanted to ask if anyone could recommend a way to troubleshoot this:
09:59:33.175 [debug] Starting apns_worker
mode: dev, cert: cert.pem, key: key.pem
I'm getting this on my local machine randomly for pigeon 0.5.1 whereas I never used to see this message in the same version.
It seems to be trying to get a connection with apns but what could be causing this?
Thanks,
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.