diff --git a/CHANGELOG.md b/CHANGELOG.md index a39bdf9..7bae528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,20 @@ # Changelog -## Unreleased +## v2.0.0-rc.3 + +### Breaking Changes + +- `Pigeon.LegacyFCM` has been removed entirely and migrated to [pigeon_legacy_fcm](https://github.com/codedge-llc/pigeon-legacy-fcm) package. +- FCM `service_account_json` config option has been removed and replaced with `:auth`, a [Goth](https://github.com/peburrows/goth) configuration. + See `Pigeon.FCM` documentation for setup and [#235](https://github.com/codedge-llc/pigeon/pull/235) for more details. **Changed** - Bump `goth` dependency to `~> 1.4.3`. ([#252](https://github.com/codedge-llc/pigeon/pull/252)) -- Fix `DispatcherWorker` missing a clause for `{:stop, reason}` in the handle_info function. + +**Fixed** + +- `DispatcherWorker` missing a clause for `{:stop, reason}` in the handle_info function. ## v2.0.0-rc.2 diff --git a/README.md b/README.md index 311a038..3c6d29e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,11 @@ > HTTP2-compliant wrapper for sending iOS and Android push notifications. [![CI](https://github.com/codedge-llc/pigeon/actions/workflows/ci.yml/badge.svg)](https://github.com/codedge-llc/pigeon/actions/workflows/ci.yml) -[![Hex.pm](http://img.shields.io/hexpm/v/pigeon.svg)](https://hex.pm/packages/pigeon) -[![Hex.pm](http://img.shields.io/hexpm/dt/pigeon.svg)](https://hex.pm/packages/pigeon) +[![Version](https://img.shields.io/hexpm/v/pigeon.svg)](https://hex.pm/packages/pigeon) +[![Total Downloads](https://img.shields.io/hexpm/dt/pigeon.svg)](https://hex.pm/packages/pigeon) +[![License](https://img.shields.io/hexpm/l/pigeon.svg)](https://github.com/codedge-llc/pigeon/blob/master/LICENSE) +[![Last Updated](https://img.shields.io/github/last-commit/codedge-llc/pigeon.svg)](https://github.com/codedge-llc/pigeon/commits/master) +[![Documentation](https://img.shields.io/badge/documentation-gray)](https://hexdocs.pm/pigeon/) _Pigeon v2.0 is in release candidate status. See [the latest stable 1.6 on Hex](https://hex.pm/packages/pigeon) or [the 1.6 branch on GitHub](https://github.com/codedge-llc/pigeon/tree/v1.6) for installation._ @@ -16,7 +19,7 @@ Add `:pigeon` and as a `mix.exs` dependency: ```elixir def deps do [ - {:pigeon, "~> 2.0.0-rc.2"} + {:pigeon, "~> 2.0.0-rc.3"} ] end ``` diff --git a/lib/pigeon.ex b/lib/pigeon.ex index cf1ff2a..06934c3 100644 --- a/lib/pigeon.ex +++ b/lib/pigeon.ex @@ -9,7 +9,6 @@ defmodule Pigeon do - `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 @@ -97,6 +96,9 @@ defmodule Pigeon do notification :: struct | no_return @spec push(pid | atom, notifications :: [notification, ...], push_opts) :: notifications :: [struct, ...] | no_return + @doc """ + Sends a push notification with given options. + """ def push(pid, notifications, opts \\ []) def push(pid, notifications, opts) when is_list(notifications) do diff --git a/lib/pigeon/adm.ex b/lib/pigeon/adm.ex index 479811c..9ea7f4f 100644 --- a/lib/pigeon/adm.ex +++ b/lib/pigeon/adm.ex @@ -4,16 +4,19 @@ defmodule Pigeon.ADM do ## Getting Started - 1. Create an ADM dispatcher. + ### Create a dispatcher. ``` - # lib/adm.ex + # lib/your_app/adm.ex + defmodule YourApp.ADM do use Pigeon.Dispatcher, otp_app: :your_app end ``` - 2. (Optional) Add configuration to your `config.exs`. + ### Configure your dispatcher. + + Configure your `ADM` dispatcher and start it on application boot. ``` # config.exs @@ -24,7 +27,7 @@ defmodule Pigeon.ADM do client_secret: "your_oauth2_client_secret_here" ``` - 3. Start your dispatcher on application boot. + Add it to your supervision tree. ``` defmodule YourApp.Application do @@ -43,7 +46,7 @@ defmodule Pigeon.ADM do end ``` - If you skipped step two, include your configuration. + If preferred, you can include your configuration directly. ``` defmodule YourApp.Application do @@ -70,14 +73,14 @@ defmodule Pigeon.ADM do end ``` - 4. Create a notification. + ### Create a notification. ``` msg = %{ "body" => "your message" } n = Pigeon.ADM.Notification.new("your device registration ID", msg) ``` - 5. Send the notification. + ### Send the notification. ``` YourApp.ADM.push(n) diff --git a/lib/pigeon/apns.ex b/lib/pigeon/apns.ex index 787638a..72e4bcd 100644 --- a/lib/pigeon/apns.ex +++ b/lib/pigeon/apns.ex @@ -4,16 +4,19 @@ defmodule Pigeon.APNS do ## Getting Started - 1. Create an `APNS` dispatcher. + ### Create a dispatcher. ``` - # lib/apns.ex + # lib/your_app/apns.ex + defmodule YourApp.APNS do use Pigeon.Dispatcher, otp_app: :your_app end ``` - 2. (Optional) Add configuration to your `config.exs`. + ### Configure your dispatcher. + + Configure your `APNS` dispatcher and start it on application boot. ``` # config.exs @@ -23,11 +26,9 @@ defmodule Pigeon.APNS do cert: File.read!("cert.pem"), key: File.read!("key_unencrypted.pem"), mode: :dev - ``` - Or use token based authentication: + # Or for token based authentication: - ``` config :your_app, YourApp.APNS, adapter: Pigeon.APNS, key: File.read!("AuthKey.p8"), @@ -36,7 +37,7 @@ defmodule Pigeon.APNS do team_id: "DEF8901234" ``` - 3. Start your dispatcher on application boot. + Add it to your supervision tree. ``` defmodule YourApp.Application do @@ -55,7 +56,7 @@ defmodule Pigeon.APNS do end ``` - If you skipped step two, include your configuration. + If preferred, you can include your configuration directly. ``` defmodule YourApp.Application do @@ -83,14 +84,19 @@ defmodule Pigeon.APNS do end ``` - 4. Create a notification. **Note: Your push topic is generally the app's bundle identifier.** + ### Create a notification. ``` n = Pigeon.APNS.Notification.new("your message", "your device token", "your push topic") ``` + + > #### Note {: .info} + > + > Note: Your push topic is generally the app's bundle identifier. - 5. Send the packet. Pushes are synchronous and return the notification with an - updated `:response` key. + ### Send the notification. + + Pushes are synchronous and return the notification with an updated `:response` key. ``` YourApp.APNS.push(n) diff --git a/lib/pigeon/fcm.ex b/lib/pigeon/fcm.ex index 3946ae8..be7f953 100644 --- a/lib/pigeon/fcm.ex +++ b/lib/pigeon/fcm.ex @@ -4,28 +4,35 @@ defmodule Pigeon.FCM do ## Getting Started - 1. Create a `FCM` dispatcher. + ### Create a dispatcher. - ``` - # lib/fcm.ex - defmodule YourApp.FCM do - use Pigeon.Dispatcher, otp_app: :your_app - end - ``` + ``` + # lib/your_app/fcm.ex + + defmodule YourApp.FCM do + use Pigeon.Dispatcher, otp_app: :your_app + end + ``` - 2. Configure the [`goth`](https://hexdocs.pm/goth/1.4.3/readme.html#installation) library, and add it to `config.exs` + ### Install and configure Goth. + + Install and configure [`goth`](https://hexdocs.pm/goth/1.4.3/readme.html#installation) + if you haven't already. `Pigeon.FCM` requires it for token authentication. + + ### Configure your dispatcher. + + Configure your `FCM` dispatcher and start it on application boot. ``` # config.exs - # See Step 3 for alternative configuration config :your_app, YourApp.FCM, adapter: Pigeon.FCM, - auth: YourApp.Goth, + auth: YourApp.Goth, # Your Goth worker configured in the previous step. project_id: "example-project-123" ``` - 3. Start your dispatcher on application boot. + Add it to your supervision tree. ``` defmodule YourApp.Application do @@ -45,7 +52,7 @@ defmodule Pigeon.FCM do end ``` - If preferred, you can include your configuration directly + If preferred, you can include your configuration directly. ``` defmodule YourApp.Application do @@ -73,13 +80,13 @@ defmodule Pigeon.FCM do end ``` - 4. Create a notification. + ### Create a notification. ``` n = Pigeon.FCM.Notification.new({:token, "reg ID"}, %{"body" => "test message"}) ``` - 5. Send the notification. + ### Send the notification. On successful response, `:name` will be set to the name returned from the FCM API and `:response` will be `:success`. If there was an error, `:error` will @@ -92,47 +99,9 @@ defmodule Pigeon.FCM do ## Customizing Goth - If you need a customizable `:auth` that handles fetching its own configuration, here's - an example you can use to get started. - - For other `:source` configurations of `YourApp.Goth`, check out the `goth` documentation for [`Goth.start_link/1`](https://hexdocs.pm/goth/Goth.html#start_link/1) - - ``` - # lib/your_app/goth.ex - defmodule YourApp.Goth - - @spec child_spec(any()) :: Supervisor.child_spec() - def child_spec(_args) do - env_opts = Keyword.new(Application.get_env(:your_app, YourApp.Goth, [])) - opts = Keyword.merge([name: YourApp.Goth], env_opts) - - %{ - :id => YourApp.Goth, - :start => {Goth, :start_link, [opts]} - } - end - end - - # config.exs - config :your_app, YourApp.Goth, source: {:metadata, []} - - # config/test.exs - config :your_app, YourApp.Goth, - source: {:metadata, []}, - http_client: {&PigeonTest.GothHttpClient.Stub.access_token_response/1, []} - - # application.exs - def start(_type, _args) do - children = [ - # The `child_spec/1` handles fetching the proper config - YourApp.Goth, - YourApp.FCM - ] - opts = [strategy: :one_for_one, name: YourApp.Supervisor] - Supervisor.start_link(children, opts) - end - ``` - + You can use any of the configuration options (e.g. `:source`) for Goth. Check out the + documentation of [`Goth.start_link/1`](https://hexdocs.pm/goth/Goth.html#start_link/1) + for more details. """ @max_retries 3 diff --git a/mix.exs b/mix.exs index ce9a9d2..4b79e92 100644 --- a/mix.exs +++ b/mix.exs @@ -2,7 +2,7 @@ defmodule Pigeon.Mixfile do use Mix.Project @source_url "https://github.com/codedge-llc/pigeon" - @version "2.0.0-rc.2" + @version "2.0.0-rc.3" def project do [ @@ -58,16 +58,23 @@ defmodule Pigeon.Mixfile do defp docs do [ + extras: [ + "CHANGELOG.md", + LICENSE: [title: "License"] + ], groups_for_modules: [ "ADM - Amazon Android": [Pigeon.ADM, Pigeon.ADM.Notification], "APNS - Apple iOS": [Pigeon.APNS, Pigeon.APNS.Notification], "FCM - Firebase Cloud Messaging": [ Pigeon.FCM, - Pigeon.FCM.Notification, - PigeonTest.GothHttpClient.Stub + Pigeon.FCM.Notification ] ], - main: "Pigeon" + formatters: ["html"], + main: "Pigeon", + skip_undefined_reference_warnings_on: ["CHANGELOG.md"], + source_ref: "v#{@version}", + source_url: @source_url ] end @@ -80,11 +87,12 @@ defmodule Pigeon.Mixfile do defp package do [ - files: ["lib", "mix.exs", "README*", "LICENSE*"], + files: ["lib", "mix.exs", "README*", "LICENSE*", "CHANGELOG*"], licenses: ["MIT"], links: %{ "Changelog" => "https://hexdocs.pm/pigeon/changelog.html", - "GitHub" => @source_url + "GitHub" => @source_url, + "Sponsor" => "https://github.com/sponsors/codedge-llc" }, maintainers: ["Henry Popp", "Tyler Hurst"] ] diff --git a/test/support/fcm.ex b/test/support/fcm.ex index 4d0d3d5..8497297 100644 --- a/test/support/fcm.ex +++ b/test/support/fcm.ex @@ -2,69 +2,3 @@ defmodule PigeonTest.FCM do @moduledoc false use Pigeon.Dispatcher, otp_app: :pigeon end - -defmodule PigeonTest.GothHttpClient.Stub do - @moduledoc """ - A collection of functions that can be used as custom `:http_client` values. Used to avoid - calling out to GCP during tests. - - - ## Usage - ``` - # lib/your_app/goth.ex - defmodule YourApp.Goth - - @spec child_spec(any()) :: Supervisor.child_spec() - def child_spec(_args) do - env_opts = Keyword.new(Application.get_env(:your_app, YourApp.Goth, [])) - opts = Keyword.merge([name: YourApp.Goth], env_opts) - - %{ - :id => YourApp.Goth, - :start => {Goth, :start_link, [opts]} - } - end - end - - # config/test.exs - # Config for the Goth genserver, YourApp.Goth - config :your_app, YourApp.Goth, - source: {:metadata, []}, - http_client: {&PigeonTest.GothHttpClient.Stub.access_token_response/1, []} - - - # application.exs - def start(_type, _args) do - children = [ - # The `child_spec/1` handles fetching the proper config - YourApp.Goth, - YourApp.FCM - ] - opts = [strategy: :one_for_one, name: YourApp.Supervisor] - Supervisor.start_link(children, opts) - end - ``` - """ - - @doc """ - Always returns a stub access_token response, as if being requested of a Google Metadata Server. - - See module documentation for usage. - """ - @spec access_token_response(keyword()) :: - {:ok, - %{ - status: pos_integer(), - headers: list(), - body: String.t() - }} - def access_token_response(_) do - body = %{ - "access_token" => "FAKE_APPLICATION_DEFAULT_CREDENTIALS_ACCESS_TOKEN", - "expires_in" => :timer.minutes(30), - "token_type" => "Bearer" - } - - {:ok, %{status: 200, headers: [], body: Jason.encode!(body)}} - end -end