Skip to content

Commit 6469f96

Browse files
committed
Add Pushy (pushy.me) support
1 parent b9f5213 commit 6469f96

File tree

11 files changed

+119
-14
lines changed

11 files changed

+119
-14
lines changed

README.md

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ notifications** to `FCM` (Firebase Cloud Messaging) and/or
1212

1313
#### Running from DockerHub
1414

15-
We provide already built MongoosePush images. If you just want to use it, then all you need is `docker`, `FCM` app token and/or `APNS` app certificates.
15+
We provide already built MongoosePush images. If you just want to use it, then all you need is `docker`, `FCM` app token and/or `APNS` app certificates and/or `Pushy` app token.
1616
In case of certificates you need to setup the following directory structure:
1717
* priv/
1818
* ssl/
@@ -24,16 +24,23 @@ In case of certificates you need to setup the following directory structure:
2424
* dev_cert.pem - Development APNS app certificate
2525
* dev_key.pem - Development APNS app certificate's private key (has to be unencrypted)
2626

27-
Assuming that your `FCM` app token is "MY_FCM_SECRET_TOKEN" and you have the `priv` directory with all ceriticates in current directory, then you may start MongoosePush with the following command:
27+
Assuming that your `FCM` app token is "MY_FCM_SECRET_TOKEN", `Pushy` app token is "MY_PUSHY_SECRET_TOKEN" and you have the `priv` directory with all ceriticates in current directory, then you may start MongoosePush with the following command:
2828

2929
```bash
3030
docker run -v `pwd`/priv:/opt/app/priv \
31+
-e PUSH_FCM_ENABLED=true \
3132
-e PUSH_FCM_APP_KEY="MY_FCM_SECRET_TOKEN" \
33+
-e PUSH_PUSHY_ENABLED=true \
34+
-e PUSH_PUSHY_APP_KEY="MY_PUSHY_SECRET_TOKEN" \
35+
-e PUSH_APNS_ENABLED=true \
3236
-e PUSH_HTTPS_CERTFILE="/opt/app/priv/ssl/rest_cert.pem" \
3337
-e PUSH_HTTPS_KEYFILE="/opt/app/priv/ssl/rest_key.pem" \
3438
-it --rm mongooseim/mongoose-push:latest
3539
```
3640

41+
Please note that each push service that is being used has to be enabled by `PUSH_FCM_ENABLED` / `PUSH_APNS_ENABLED` / `PUSH_PUSHY_ENABLED` as
42+
all services are disabled by default. In the example above, we enable all push services, but you may want to skip some of them.
43+
3744
#### Building
3845

3946
Building docker is really easy, just type:
@@ -64,14 +71,20 @@ Environmental variables to configure production release:
6471

6572
##### General settings:
6673
* `PUSH_LOGLEVEL` - `debug`/`info`/`warn`/`error` - Log level of the application. `info` is the default one
67-
* `PUSH_FCM_ENABLED` - `true`/`false` - Enable or disable `FCM` support. Enabled by default
68-
* `PUSH_APNS_ENABLED` - `true`/`false` - Enable or disable `APNS` support. Enabled by default
74+
* `PUSH_FCM_ENABLED` - `true`/`false` - Enable or disable `FCM` support. Disabled by default
75+
* `PUSH_APNS_ENABLED` - `true`/`false` - Enable or disable `APNS` support. Disabled by default
76+
* `PUSH_PUSHY_ENABLED` - `true`/`false` - Enable or disable `Pushy` support. Disabled by default
6977

7078
##### Settings for FCM service:
7179
* `PUSH_FCM_ENDPOINT` - Hostname of `FCM` service. Set only for local testing. By default this option points to the Google's official hostname
7280
* `PUSH_FCM_APP_KEY` - App key token to use with `FCM` service
7381
* `PUSH_FCM_POOL_SIZE` - Connection pool size for `FCM` service
7482

83+
##### Settings for Pushy service:
84+
* `PUSH_PUSHY_ENDPOINT` - Hostname of `Pushy` service. Set only for local testing. By default this option points to the Google's official hostname
85+
* `PUSH_PUSHY_APP_KEY` - App key token to use with `Pushy` service
86+
* `PUSH_PUSHY_POOL_SIZE` - Connection pool size for `Pushy` service. Please note that `Pushy` uses HTTP 1.1, so the pool size has be be significantly bigger then in case of other services that run on HTTP/2
87+
7588
##### Settings for development APNS service:
7689
* `PUSH_APNS_DEV_ENDPOINT` - Hostname of `APNS` service. Set only for local testing. By default this option points to the Apple's official hostname
7790
* `PUSH_APNS_DEV_CERT` - Path Apple's development certfile used to communicate with `APNS`
@@ -159,6 +172,28 @@ Each `FCM` pool may be configured by setting the following fields:
159172

160173
You may entirely skip the `FCM` config entry to disable `FCM` support.
161174

175+
### Pushy configuration
176+
Lets take a look at sample `Pushy` service configuration:
177+
```elixir
178+
config :mongoose_push, pushy: [
179+
default: [
180+
key: "fake_app_key",
181+
pool_size: 50,
182+
mode: :prod
183+
]
184+
]
185+
```
186+
187+
This is a definition of a pool - each pool has a name and configuration. It is possible to have multiple named pools with different configuration, which includes pool size, environment mode etc. Currently the only reason you may want to do this, is to create separate production and development pools which may be selected by an `HTTP` client by specifying matching `:mode` in their push request.
188+
189+
Each `Pushy` pool may be configured by setting the following fields:
190+
* **key** (*required*) - you `Pushy` Server Key
191+
* **pool_size** (*required*) - maximum number of used `HTTP 1.1` connections to Pushy service
192+
* **mode** (*either `:prod` or `:dev`*) - pool's mode. The `HTTP` client may select pool used to push a notification by specifying matching option in the request
193+
* **endpoint** (*optional*) - URL override for `Pushy` service. Useful mainly in tests
194+
195+
You may entirely skip the `Pushy` config entry to disable `Pushy` support.
196+
162197
### APNS configuration
163198

164199
Lets take a look at sample `APNS` service configuration:

config/prod.exs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ config :maru, MongoosePush.Router,
1717

1818
config :mongoose_push, loglevel:
1919
{:system, :atom, "PUSH_LOGLEVEL", :info}
20+
21+
config :mongoose_push, pushy_enabled:
22+
{:system, :boolean, "PUSH_PUSHY_ENABLED", false}
23+
2024
config :mongoose_push, fcm_enabled:
21-
{:system, :boolean, "PUSH_FCM_ENABLED", true}
25+
{:system, :boolean, "PUSH_FCM_ENABLED", false}
2226

2327
config :mongoose_push, apns_enabled:
24-
{:system, :boolean, "PUSH_APNS_ENABLED", true}
28+
{:system, :boolean, "PUSH_APNS_ENABLED", false}
2529

2630
config :mongoose_push, fcm: [
2731
default: [
@@ -32,6 +36,15 @@ config :mongoose_push, fcm: [
3236
]
3337
]
3438

39+
config :mongoose_push, pushy: [
40+
default: [
41+
endpoint: {:system, :string, "PUSH_PUSHY_ENDPOINT", nil},
42+
key: {:system, :string, "PUSH_PUSHY_APP_KEY", "fake_app_key"},
43+
pool_size: {:system, :integer, "PUSH_PUSHY_POOL_SIZE", 100},
44+
mode: :prod,
45+
]
46+
]
47+
3548
config :mongoose_push, apns: [
3649
dev: [
3750
endpoint: {:system, :string, "PUSH_APNS_DEV_ENDPOINT", nil},

lib/mongoose_push/api.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ defmodule MongoosePush.API do
1616
{500, %{:details => reason}}
1717
end
1818
end
19+
def to_status({:error, reason}) when is_binary(reason) do
20+
{400, reason}
21+
end
1922
def to_status({:error, _reason}) do
2023
{500, nil}
2124
end

lib/mongoose_push/api/v1.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule MongoosePush.API.V1 do
1010
parsers: [:urlencoded, :json, :multipart]
1111

1212
params do
13-
requires :service, type: Atom, values: [:fcm, :apns]
13+
requires :service, type: Atom, values: [:fcm, :apns, :pushy]
1414
requires :body, type: String
1515
requires :title, type: String
1616
optional :badge, type: Integer

lib/mongoose_push/api/v2.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule MongoosePush.API.V2 do
1010
parsers: [:urlencoded, :json, :multipart]
1111

1212
params do
13-
requires :service, type: Atom, values: [:fcm, :apns]
13+
requires :service, type: Atom, values: [:fcm, :apns, :pushy]
1414
optional :mode, type: Atom, values: [:prod, :dev]
1515
optional :priority, type: Atom, values: [:normal, :high]
1616
optional :time_to_live, type: Integer

lib/mongoose_push/application.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ defmodule MongoosePush.Application do
4343
def services do
4444
[
4545
fcm: MongoosePush.Service.FCM,
46-
apns: MongoosePush.Service.APNS
46+
apns: MongoosePush.Service.APNS,
47+
pushy: MongoosePush.Service.Pushy
4748
]
4849
end
4950

@@ -68,7 +69,7 @@ defmodule MongoosePush.Application do
6869
case service do
6970
:apns ->
7071
[:cert, :key]
71-
:fcm ->
72+
_ ->
7273
[]
7374
end
7475
config

lib/mongoose_push/pools.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ defmodule MongoosePush.Pools do
2424
Enum.map(config, &(elem(&1, 0)))
2525
end
2626

27+
@spec pools_by_mode(MongoosePush.service, MongoosePush.mode) :: list(atom)
28+
def pools_by_mode(:pushy = service, _mode) do
29+
config = pools_config(service)
30+
Enum.map(config, &(elem(&1, 0)))
31+
end
32+
2733
def pools_by_mode(:apns = service, mode) do
2834
config = pools_config(service)
2935

lib/mongoose_push/service/fcm.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ defmodule MongoosePush.Service.FCM do
2626
|> Enum.reduce(%{}, fn(field, map) ->
2727
Map.put(map, field, alert[field])
2828
end)
29+
|> Enum.filter(fn({_, value}) -> value != nil end)
30+
|> Map.new()
2931

3032
Notification.new(device_id, msg, request[:data])
3133
|> Notification.put_priority(@priority_mapping[request[:priority]])

lib/mongoose_push/service/pushy.ex

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
defmodule MongoosePush.Service.Pushy do
2+
@moduledoc """
3+
Pushy service provider implementation.
4+
"""
5+
6+
@behaviour MongoosePush.Service
7+
alias MongoosePush.Pools
8+
require Logger
9+
10+
@spec prepare_notification(String.t(), MongoosePush.request) ::
11+
Service.notification
12+
def prepare_notification(device_id, request) do
13+
MongoosePush.Service.FCM.prepare_notification(device_id, request)
14+
end
15+
16+
@spec push(Service.notification(), String.t(), atom(), Service.options()) ::
17+
:ok | {:error, term}
18+
def push(notification, device_id, worker, opts \\ []) do
19+
MongoosePush.Service.FCM.push(notification, device_id, worker, opts)
20+
end
21+
22+
@spec workers({atom, Keyword.t()} | nil) :: list(Supervisor.Spec.spec())
23+
def workers(nil), do: []
24+
def workers({pool_name, pool_config}) do
25+
Logger.info ~s"Starting Pushy pool with API key #{filter_secret(pool_config[:key])}"
26+
pool_size = pool_config[:pool_size]
27+
Enum.map(1..pool_size, fn(id) ->
28+
worker_name = Pools.worker_name(:pushy, pool_name, id)
29+
Supervisor.Spec.worker(Pigeon.PushyWorker,
30+
[worker_name, pool_config], [id: worker_name])
31+
end)
32+
end
33+
34+
defp filter_secret(secret) when is_binary(secret) do
35+
prefix = String.slice(secret, 0..2)
36+
suffix =
37+
secret
38+
|> String.slice(3..-1)
39+
|> String.slice(-3..-1)
40+
41+
prefix <> "*******" <> suffix
42+
end
43+
defp filter_secret(secret), do: secret
44+
45+
end

mix.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ defmodule MongoosePush.Mixfile do
2525

2626
defp deps do
2727
[
28-
{:pigeon, github: "rslota/pigeon", ref: "2860eee35b58e2d8674f805f1151f57b9faeca21"},
28+
{:pigeon, github: "rslota/pigeon", ref: "fa7fa5e"},
2929
{:chatterbox, github: "joedevivo/chatterbox", ref: "ff0c2e0", override: true},
3030

3131
{:maru, github: "rslota/maru", ref: "54fc038", override: true},
@@ -51,7 +51,7 @@ defmodule MongoosePush.Mixfile do
5151
# Until eproxus/meck #fcc551e3 is in a release, we need to use master version
5252
# to include this commit (fixes mocking in Erlang 20.x + Elixir 1.5.x)
5353
{:meck, github: "eproxus/meck", override: true},
54-
{:httpoison, "~> 0.13"},
54+
{:httpoison, "~> 1.4"},
5555
{:excoveralls, "~> 0.7", only: :test},
5656
{:dialyxir, "~> 0.4", only: [:dev, :test], runtime: false},
5757
{:credo, "~> 0.5", only: [:dev, :test]},

mix.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
2222
"hackney": {:hex, :hackney, "1.11.0", "4951ee019df102492dabba66a09e305f61919a8a183a7860236c0fde586134b6", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
2323
"hpack": {:git, "https://github.com/joedevivo/hpack.git", "6b58b6231e9b6ab83096715120578976f72f4f7c", [tag: "0.2.3"]},
24-
"httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
24+
"httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
2525
"hut": {:hex, :hut, "1.2.0", "0089df0faa2827c605bbada88153f24fff5ea7a4be32ecf0250a7fdc2719cafb", [:"erlang.mk", :rebar, :rebar3], [], "hexpm"},
2626
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
2727
"jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
@@ -37,7 +37,7 @@
3737
"mix_docker": {:hex, :mix_docker, "0.5.0", "c7ad34008c43d4a949d69721f39c4d2a2afc509c179926a683117ea8dff8af59", [:mix], [{:distillery, "~> 1.2", [hex: :distillery, repo: "hexpm", optional: false]}], "hexpm"},
3838
"mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
3939
"parse_trans": {:hex, :parse_trans, "3.1.0", "1bad3b959941cc53ffd6f4769a5d2666f9cdf179b2d62826636497d3fbad9ec0", [:rebar3], [], "hexpm"},
40-
"pigeon": {:git, "https://github.com/rslota/pigeon.git", "2860eee35b58e2d8674f805f1151f57b9faeca21", [ref: "2860eee35b58e2d8674f805f1151f57b9faeca21"]},
40+
"pigeon": {:git, "https://github.com/rslota/pigeon.git", "fa7fa5e8686477c1ce19a7592bf4f13d994bc0f2", [ref: "fa7fa5e"]},
4141
"plug": {:hex, :plug, "1.5.0", "224b25b4039bedc1eac149fb52ed456770b9678bbf0349cdd810460e1e09195b", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
4242
"pobox": {:hex, :pobox, "1.0.4", "e695bc3b2b547dd6c8e5a19cb743396e6670e306ad3ff498844738f9418bd686", [:rebar3], [], "hexpm"},
4343
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},

0 commit comments

Comments
 (0)