Skip to content

[Do not merge][WIP] Add Pushy (pushy.me) support #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: release/1.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ notifications** to `FCM` (Firebase Cloud Messaging) and/or

#### Running from DockerHub

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.
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.
In case of certificates you need to setup the following directory structure:
* priv/
* ssl/
Expand All @@ -24,16 +24,23 @@ In case of certificates you need to setup the following directory structure:
* dev_cert.pem - Development APNS app certificate
* dev_key.pem - Development APNS app certificate's private key (has to be unencrypted)

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:
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 certificates in current directory, then you may start MongoosePush with the following command:

```bash
docker run -v `pwd`/priv:/opt/app/priv \
-e PUSH_FCM_ENABLED=true \
-e PUSH_FCM_APP_KEY="MY_FCM_SECRET_TOKEN" \
-e PUSH_PUSHY_ENABLED=true \
-e PUSH_PUSHY_APP_KEY="MY_PUSHY_SECRET_TOKEN" \
-e PUSH_APNS_ENABLED=true \
-e PUSH_HTTPS_CERTFILE="/opt/app/priv/ssl/rest_cert.pem" \
-e PUSH_HTTPS_KEYFILE="/opt/app/priv/ssl/rest_key.pem" \
-it --rm mongooseim/mongoose-push:latest
```

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
all services are disabled by default. In the example above, we enable all push services, but you may want to skip some of them.

#### Building

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

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

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

##### Settings for Pushy service:
* `PUSH_PUSHY_ENDPOINT` - Hostname of `Pushy` service. Set only for local testing. By default this option points to the Google's official hostname
* `PUSH_PUSHY_APP_KEY` - App key token to use with `Pushy` service
* `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

##### Settings for development APNS service:
* `PUSH_APNS_DEV_ENDPOINT` - Hostname of `APNS` service. Set only for local testing. By default this option points to the Apple's official hostname
* `PUSH_APNS_DEV_CERT` - Path Apple's development certfile used to communicate with `APNS`
Expand Down Expand Up @@ -159,6 +172,28 @@ Each `FCM` pool may be configured by setting the following fields:

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

### Pushy configuration
Lets take a look at sample `Pushy` service configuration:
```elixir
config :mongoose_push, pushy: [
default: [
key: "fake_app_key",
pool_size: 50,
mode: :prod
]
]
```

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.

Each `Pushy` pool may be configured by setting the following fields:
* **key** (*required*) - you `Pushy` Server Key
* **pool_size** (*required*) - maximum number of used `HTTP 1.1` connections to Pushy service
* **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
* **endpoint** (*optional*) - URL override for `Pushy` service. Useful mainly in tests

You may entirely skip the `Pushy` config entry to disable `Pushy` support.

### APNS configuration

Lets take a look at sample `APNS` service configuration:
Expand Down
23 changes: 23 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ config :plug, :statuses, %{
460 => "Invalid device token"
}

lager_formater_config = [:date, 'T', :time, :color, ' [', :severity, '] ', :pid, ' ', :message, '\e[0m\r\n']
config :lager,
colored: true,
handlers: [
lager_console_backend: [
level: :info,
formatter: :lager_default_formatter,
formatter_config: lager_formater_config
],
lager_file_backend: [
file: 'log/error.log',
level: :error,
formatter: :lager_default_formatter,
formatter_config: lager_formater_config
],
lager_file_backend: [
file: 'log/console.log',
level: :info,
formatter: :lager_default_formatter,
formatter_config: lager_formater_config
]
]

import_config "#{Mix.env}.exs"

# Globally disable maru's "test mode". If we don't disable it explicitly
Expand Down
17 changes: 15 additions & 2 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ config :maru, MongoosePush.Router,

config :mongoose_push, loglevel:
{:system, :atom, "PUSH_LOGLEVEL", :info}

config :mongoose_push, pushy_enabled:
{:system, :boolean, "PUSH_PUSHY_ENABLED", false}

config :mongoose_push, fcm_enabled:
{:system, :boolean, "PUSH_FCM_ENABLED", true}
{:system, :boolean, "PUSH_FCM_ENABLED", false}

config :mongoose_push, apns_enabled:
{:system, :boolean, "PUSH_APNS_ENABLED", true}
{:system, :boolean, "PUSH_APNS_ENABLED", false}

config :mongoose_push, fcm: [
default: [
Expand All @@ -32,6 +36,15 @@ config :mongoose_push, fcm: [
]
]

config :mongoose_push, pushy: [
default: [
endpoint: {:system, :string, "PUSH_PUSHY_ENDPOINT", nil},
key: {:system, :string, "PUSH_PUSHY_APP_KEY", "fake_app_key"},
pool_size: {:system, :integer, "PUSH_PUSHY_POOL_SIZE", 100},
mode: :prod,
]
]

config :mongoose_push, apns: [
dev: [
endpoint: {:system, :string, "PUSH_APNS_DEV_ENDPOINT", nil},
Expand Down
3 changes: 3 additions & 0 deletions lib/mongoose_push/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ defmodule MongoosePush.API do
{500, %{:details => reason}}
end
end
def to_status({:error, reason}) when is_binary(reason) do
{400, reason}
end
def to_status({:error, _reason}) do
{500, nil}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoose_push/api/v1.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule MongoosePush.API.V1 do
parsers: [:urlencoded, :json, :multipart]

params do
requires :service, type: Atom, values: [:fcm, :apns]
requires :service, type: Atom, values: [:fcm, :apns, :pushy]
requires :body, type: String
requires :title, type: String
optional :badge, type: Integer
Expand Down
2 changes: 1 addition & 1 deletion lib/mongoose_push/api/v2.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule MongoosePush.API.V2 do
parsers: [:urlencoded, :json, :multipart]

params do
requires :service, type: Atom, values: [:fcm, :apns]
requires :service, type: Atom, values: [:fcm, :apns, :pushy]
optional :mode, type: Atom, values: [:prod, :dev]
optional :priority, type: Atom, values: [:normal, :high]
optional :time_to_live, type: Integer
Expand Down
5 changes: 3 additions & 2 deletions lib/mongoose_push/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ defmodule MongoosePush.Application do
def services do
[
fcm: MongoosePush.Service.FCM,
apns: MongoosePush.Service.APNS
apns: MongoosePush.Service.APNS,
pushy: MongoosePush.Service.Pushy
]
end

Expand All @@ -68,7 +69,7 @@ defmodule MongoosePush.Application do
case service do
:apns ->
[:cert, :key]
:fcm ->
_ ->
[]
end
config
Expand Down
6 changes: 6 additions & 0 deletions lib/mongoose_push/pools.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ defmodule MongoosePush.Pools do
Enum.map(config, &(elem(&1, 0)))
end

@spec pools_by_mode(MongoosePush.service, MongoosePush.mode) :: list(atom)
def pools_by_mode(:pushy = service, _mode) do
config = pools_config(service)
Enum.map(config, &(elem(&1, 0)))
end

def pools_by_mode(:apns = service, mode) do
config = pools_config(service)

Expand Down
4 changes: 2 additions & 2 deletions lib/mongoose_push/service/apns.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ defmodule MongoosePush.Service.APNS do
:dev -> :development_endpoint
:prod -> :production_endpoint
end
Keyword.merge([{new_key, config[:endpoint]}], config)
Keyword.put(config, new_key, config[:endpoint])
end

defp announce_subject(config) do
Expand All @@ -101,7 +101,7 @@ defmodule MongoosePush.Service.APNS do
all_topics = Certificate.extract_topics!(config[:cert])
default_topic = all_topics[:topic]
Logger.info(~s"Successfully extracted default APNS topic: #{default_topic}")
Keyword.merge([default_topic: default_topic], config)
Keyword.put(config, :default_topic, default_topic)
default_topic ->
Logger.info(~s"Using user-defined default APNS topic: #{default_topic}")
config
Expand Down
2 changes: 2 additions & 0 deletions lib/mongoose_push/service/fcm.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ defmodule MongoosePush.Service.FCM do
|> Enum.reduce(%{}, fn(field, map) ->
Map.put(map, field, alert[field])
end)
|> Enum.filter(fn({_, value}) -> value != nil end)
|> Map.new()

Notification.new(device_id, msg, request[:data])
|> Notification.put_priority(@priority_mapping[request[:priority]])
Expand Down
45 changes: 45 additions & 0 deletions lib/mongoose_push/service/pushy.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule MongoosePush.Service.Pushy do
@moduledoc """
Pushy service provider implementation.
"""

@behaviour MongoosePush.Service
alias MongoosePush.Pools
require Logger

@spec prepare_notification(String.t(), MongoosePush.request) ::
Service.notification
def prepare_notification(device_id, request) do
MongoosePush.Service.FCM.prepare_notification(device_id, request)
end

@spec push(Service.notification(), String.t(), atom(), Service.options()) ::
:ok | {:error, term}
def push(notification, device_id, worker, opts \\ []) do
MongoosePush.Service.FCM.push(notification, device_id, worker, opts)
end

@spec workers({atom, Keyword.t()} | nil) :: list(Supervisor.Spec.spec())
def workers(nil), do: []
def workers({pool_name, pool_config}) do
Logger.info ~s"Starting Pushy pool with API key #{filter_secret(pool_config[:key])}"
pool_size = pool_config[:pool_size]
Enum.map(1..pool_size, fn(id) ->
worker_name = Pools.worker_name(:pushy, pool_name, id)
Supervisor.Spec.worker(Pigeon.PushyWorker,
[worker_name, pool_config], [id: worker_name])
end)
end

defp filter_secret(secret) when is_binary(secret) do
prefix = String.slice(secret, 0..2)
suffix =
secret
|> String.slice(3..-1)
|> String.slice(-3..-1)

prefix <> "*******" <> suffix
end
defp filter_secret(secret), do: secret

end
10 changes: 5 additions & 5 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ defmodule MongoosePush.Mixfile do

defp deps do
[
{:chatterbox, github: "joedevivo/chatterbox", ref: "ff0c2e054430d2990b588afa6fb8f2d184dfeaea", override: true},
{:pigeon, github: "rslota/pigeon", ref: "2860eee35b58e2d8674f805f1151f57b9faeca21"},
{:pigeon, github: "rslota/pigeon", ref: "3c83127f25a638b0dd0324742daeb282defd5dc7"},
{:chatterbox, github: "joedevivo/chatterbox", ref: "ff0c2e0", override: true},

{:maru, github: "rslota/maru", ref: "54fc038", override: true},
{:cowboy, "~> 2.3", override: true},
Expand All @@ -38,7 +38,7 @@ defmodule MongoosePush.Mixfile do
{:confex, "~> 3.2", override: true},
{:mix_docker, "~> 0.5"},
{:uuid, "~> 1.1"},
{:lager, ">= 3.6.9", override: true},
{:lager, ">= 3.7.0", override: true},
{:logger_lager_backend, "~> 0.1.0"},

# Just overrides to make elixometer compile...
Expand All @@ -51,7 +51,7 @@ defmodule MongoosePush.Mixfile do
# Until eproxus/meck #fcc551e3 is in a release, we need to use master version
# to include this commit (fixes mocking in Erlang 20.x + Elixir 1.5.x)
{:meck, github: "eproxus/meck", override: true},
{:httpoison, "~> 0.13"},
{:httpoison, "~> 1.4"},
{:excoveralls, "~> 0.7", only: :test},
{:dialyxir, "~> 0.4", only: [:dev, :test], runtime: false},
{:credo, "~> 0.5", only: [:dev, :test]},
Expand Down Expand Up @@ -79,7 +79,7 @@ defmodule MongoosePush.Mixfile do
end

defp preferred_cli_env do
["coveralls": :test, "coveralls.detail": :test,
[coveralls: :test, "coveralls.detail": :test,
"coveralls.travis": :test, "coveralls.html": :test]
end

Expand Down
12 changes: 6 additions & 6 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
%{
"artificery": {:hex, :artificery, "0.4.1", "90b1fcedb9034853b36dbea2174f9fc1172bd50b0686a723178103def5c9c1c8", [:mix], [], "hexpm"},
"artificery": {:hex, :artificery, "0.4.2", "3ded6e29e13113af52811c72f414d1e88f711410cac1b619ab3a2666bbd7efd4", [:mix], [], "hexpm"},
"bear": {:hex, :bear, "0.8.5", "e95fca1627cd9e15baf93ce0a52aff16917baf325f0ee65b88cd715376cd2344", [:rebar3], [], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [:rebar3], [], "hexpm"},
"chatterbox": {:git, "https://github.com/joedevivo/chatterbox.git", "ff0c2e054430d2990b588afa6fb8f2d184dfeaea", [ref: "ff0c2e054430d2990b588afa6fb8f2d184dfeaea"]},
"chatterbox": {:git, "https://github.com/joedevivo/chatterbox.git", "ff0c2e054430d2990b588afa6fb8f2d184dfeaea", [ref: "ff0c2e0"]},
"confex": {:hex, :confex, "3.3.1", "8febaf751bf293a16a1ed2cbd258459cdcc7ca53cfa61d3f83d49dd276a992b4", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.3.0", "268429481d6f41ad5564ade4a2439c284b569083fca0d19078ad4f56b4624724", [:rebar3], [{:cowlib, "~> 2.2.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.4.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.2.1", "1afa5b233cee8f642c153ec6f1dc48db0dd9a43e2114bc8b43e9d59636f6ae1f", [:rebar3], [], "hexpm"},
"credo": {:hex, :credo, "0.9.3", "76fa3e9e497ab282e0cf64b98a624aa11da702854c52c82db1bf24e54ab7c97a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"},
"distillery": {:hex, :distillery, "2.0.12", "6e78fe042df82610ac3fa50bd7d2d8190ad287d120d3cd1682d83a44e8b34dfb", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm"},
"distillery": {:hex, :distillery, "2.0.14", "25fc1cdad06282334dbf4a11b6e869cc002855c4e11825157498491df2eed594", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
"elixometer": {:git, "https://github.com/esl/elixometer.git", "6678c97f64ac8a4cf7ecbf32a4d342576d466b69", []},
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
Expand All @@ -21,12 +21,12 @@
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
"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"},
"hpack": {:git, "https://github.com/joedevivo/hpack.git", "6b58b6231e9b6ab83096715120578976f72f4f7c", [tag: "0.2.3"]},
"httpoison": {:hex, :httpoison, "0.13.0", "bfaf44d9f133a6599886720f3937a7699466d23bb0cd7a88b6ba011f53c6f562", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"hut": {:hex, :hut, "1.2.0", "0089df0faa2827c605bbada88153f24fff5ea7a4be32ecf0250a7fdc2719cafb", [:"erlang.mk", :rebar, :rebar3], [], "hexpm"},
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"},
"lager": {:hex, :lager, "3.6.9", "387bcd836dc0c8ad9c6d90a0e0ce5b29676847950cbc527bccc194a02028de8e", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"lager": {:hex, :lager, "3.7.0", "563ab17cd32134a3dd17ec3b3622e6d8f827506aa4f8c489158879bed87d980b", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"logger_lager_backend": {:hex, :logger_lager_backend, "0.1.0", "4858d5ac26a3a6085274933bf8b3061973cadac4adbe8e0181933e8cece78abb", [:mix], [{:lager, "~> 3.2", [hex: :lager, repo: "hexpm", optional: false]}], "hexpm"},
"maru": {:git, "https://github.com/rslota/maru.git", "54fc0380cd4b7c8b597429d1fa70c2f08a714c01", [ref: "54fc038"]},
"maru_swagger": {:git, "https://github.com/elixir-maru/maru_swagger.git", "e3dfad2bd01d50566c041dee3fcb4af375918244", []},
Expand All @@ -37,7 +37,7 @@
"mix_docker": {:hex, :mix_docker, "0.5.0", "c7ad34008c43d4a949d69721f39c4d2a2afc509c179926a683117ea8dff8af59", [:mix], [{:distillery, "~> 1.2", [hex: :distillery, repo: "hexpm", optional: false]}], "hexpm"},
"mock": {:hex, :mock, "0.3.1", "994f00150f79a0ea50dc9d86134cd9ebd0d177ad60bd04d1e46336cdfdb98ff9", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.1.0", "1bad3b959941cc53ffd6f4769a5d2666f9cdf179b2d62826636497d3fbad9ec0", [:rebar3], [], "hexpm"},
"pigeon": {:git, "https://github.com/rslota/pigeon.git", "2860eee35b58e2d8674f805f1151f57b9faeca21", [ref: "2860eee35b58e2d8674f805f1151f57b9faeca21"]},
"pigeon": {:git, "https://github.com/rslota/pigeon.git", "fa7fa5e8686477c1ce19a7592bf4f13d994bc0f2", [ref: "fa7fa5e"]},
"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"},
"pobox": {:hex, :pobox, "1.0.4", "e695bc3b2b547dd6c8e5a19cb743396e6670e306ad3ff498844738f9418bd686", [:rebar3], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
Expand Down