项目作者: danhper

项目描述 :
Push notifications for Elixir
高级语言: Elixir
项目地址: git://github.com/danhper/pushex.git
创建时间: 2016-03-27T11:27:35Z
项目社区:https://github.com/danhper/pushex

开源协议:MIT License

下载


Pushex

Build Status
Coverage Status

Pushex is a library to easily send push notifications with Elixir.

About

Goals

The main goals are the following:

  • Easy to use async API
  • Common API for iOS and Android
  • Multiple applications handling
  • Proper error and response handling
  • Testable using a sanbox mode

Status

Both GCM and APNS are working. APNS delegates to apns4ex
for now, I will probably use the HTTP2 API in a later version.

The API is still subject to change, with a minor version bump for each change.

Installation

Add the following to your dependencies mix.ex.

  1. [{:pushex, "~> 0.2"}]

Then, add :pushex to your applications.

Usage

The most basic usage, with no configuration looks like this:

  1. app = %Pushex.GCM.App{name: "a_unique_name_you_like", auth_key: "a GCM API auth key"}
  2. Pushex.push(%{title: "my_title", body: "my_body"}, to: "registration_id", with_app: app)

To avoid having to create or retreive your app each time, you can configure as many apps
as you want in your config.exs:

  1. config :pushex,
  2. gcm: [
  3. default_app: "first_app",
  4. apps: [
  5. [name: "first_app", auth_key: "a key"],
  6. [name: "other_app", auth_key: "another key"]
  7. ]
  8. ],
  9. apns: [
  10. default_app: "first_app",
  11. apps: [
  12. [name: "first_app", env: :dev, certfile: "/path/to/certfile", pool_size: 5]
  13. ]
  14. ]

You can then do the following:

  1. # this will use the default app, "first_app" with the above configuration
  2. Pushex.push(%{title: "my_title", body: "my_body"}, to: "registration_id", using: :gcm)
  3. # this will use the other_app
  4. Pushex.push(%{title: "my_title", body: "my_body"}, to: "registration_id", using: :gcm, with_app: "other_app")

Note that the function is async and only returns a reference, see the response and error
handling documentation for more information.

Sending to multiple platforms

If you want to use the same message for both platforms, you can define messages as follow:

  1. message = %{
  2. common: "this will be in both payloads",
  3. other: "this will also be in both payloads",
  4. apns: %{
  5. alert: "My alert",
  6. badge: 1
  7. },
  8. gcm: %{
  9. title: "GCM title",
  10. body: "My body"
  11. }
  12. }
  13. Pushex.push(message, to: ["apns_token1", "apns_token2"], using: :apns)
  14. Pushex.push(message, to: ["gcm_registration_id1", "gcm_registration_id2"], using: :gcm)

Only :gcm and :apns are currently available.

Passing more options

If you need to pass options, priority for example, you can just pass
it in the keyword list and it will be sent.

See

https://developers.google.com/cloud-messaging/http-server-ref#downstream-http-messages-json

for more information.

The parameters from Table 1 should be passed in the keyword list, while
the parameters from Table 2 should be passed in the first argument.

For more information about APNS options, see apns4ex docs.

NOTE: if you pass an array to the to parameter, if will automatically
be converted to registration_ids when sending the request, to keep a consistent API.

Loading app from somewhere else

If you are saving your auth_keys in your database, you can override the default way to retreive the apps:

  1. # config.exs
  2. config :pushex,
  3. app_manager_impl: MyAppManager
  4. # my_app_manager.ex
  5. defmodule MyAppManager do
  6. @behaviour Pushex.AppManager
  7. def find_app(platform, name) do
  8. if app = Repo.get_by(App, platform: platform, name: name) do
  9. make_app(platform, app)
  10. end
  11. end
  12. # transform to a `Pushex._.App`
  13. defp make_app(:gcm, app) do
  14. struct(Pushex.GCM.App, Map.from_struct(app))
  15. end
  16. defp make_app(:apns, app) do
  17. struct(Pushex.APNS.App, Map.from_struct(app))
  18. end
  19. end

Handling responses

To handle responses, you can define a module using Pushex.EventHandler
which uses :gen_event to process events.

  1. # config.exs
  2. config :pushex,
  3. event_handlers: [MyEventHandler]
  4. # my_event_handler.ex
  5. defmodule MyEventHandler do
  6. use Pushex.EventHandler
  7. def handle_event({:request, request, {pid, ref}}, state) do
  8. # do whatever you want with the request
  9. # for example, logging or saving in a DB
  10. {:ok, state}
  11. end
  12. def handle_event({:response, response, request, {pid, ref}}, state) do
  13. # do whatever you want with the response and request
  14. {:ok, state}
  15. end
  16. end

The ref passed here is the one returned when calling push.

Testing

Pushex offers a sandbox mode to make testing easier.

To enable it, you should add the following to your configuration:

  1. config :pushex,
  2. sandbox: true

Once you are using the sandbox, the messages will not be sent to GCM or APNS anymore,
but stored in Pushex.Sandbox. Furthermore, all the messages will be returned
to the process that sent them.
Here is a sample test.

  1. test "send notification to users" do
  2. ref = Pushex.push(%{body: "my message"}, to: "my-user", using: :gcm)
  3. pid = self()
  4. assert_receive {{:ok, response}, request, ^ref}
  5. assert [{{:ok, ^response}, ^request, {^pid, ^ref}}] = Pushex.Sandbox.list_notifications
  6. end

Note that list_notifications depends on the running process, so
if you call it from another process, you need to explicitly pass the pid with the :pid option.

Also note that Pushex.push is asynchronous, so if you
remove the assert_receive, you will have a race condition.
To avoid this, you can use Pushex.Sandbox.wait_notifications/1 instead of Pushex.Sandbox.list_notifications.
It will wait (by default for 100ms) until at least :count notifications arrive

  1. test "send notification to users and wait" do
  2. Enum.each (1..10), fn _ ->
  3. Pushex.push(%{body: "foo"}, to: "whoever", using: :gcm)
  4. end
  5. notifications = Pushex.Sandbox.wait_notifications(count: 10, timeout: 50)
  6. assert length(notifications) == 10
  7. end

However, the requests are asynchronous, so there is no guaranty that the notifications
in the sandbox will in the same order they have been sent.