Skip to content
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

Upgrade #142

Merged
merged 5 commits into from
Jul 13, 2019
Merged
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
9 changes: 9 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
inputs: [
"lib/**/*.{ex,exs}",
"test/**/*.{ex,exs}",
"mix.exs"
],

locals_without_parens: []
]
21 changes: 13 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
language: elixir

otp_release:
- 20.0
elixir:
- 1.5.1
cache:
directories:
- deps

matrix:
include:
- elixir: 1.9
otp_release: 21.0
- elixir: 1.9
otp_release: 22.0.1
sudo: false
env:
- MIX_ENV=test
env:
matrix:
- POXA_REGISTRY_ADAPTER=gproc
Expand All @@ -15,8 +19,9 @@ before_script:
- export PLT_FILENAME=elixir-$TRAVIS_ELIXIR_VERSION-$TRAVIS_OTP_RELEASE.plt
- wget -O .local.plt https://s3.amazonaws.com/poxa-plt/travis_elixir_plts/$PLT_FILENAME || true
script:
- MIX_ENV=test mix test --no-start --trace --exclude integration
- MIX_ENV=test mix test --trace --only integration
- mix test --no-start --trace
- mix test --trace --only integration
- mix format --check-formatted
- mix dialyzer -o dialyzer.out && cat dialyzer.out || true
after_script:
- PULL_REQUEST_ID=$TRAVIS_PULL_REQUEST pronto run -f github_pr -c origin/master
Expand Down
50 changes: 28 additions & 22 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
FROM elixir:1.5.2-alpine AS builder
# Based on https://github.com/hexpm/hexpm/blob/08e80ed4fe82b145f6cee1d01da16e162add2a56/Dockerfile
FROM elixir:1.9.0-alpine as build

ENV APP_NAME poxa
ENV MIX_ENV prod
ENV MIX_ENV=prod

RUN apk --no-cache add git erlang-xmerl erlang-crypto erlang-sasl
RUN mkdir /app
WORKDIR /app

COPY . /source
WORKDIR /source
RUN mix local.hex --force && mix local.rebar --force

RUN mix do \
local.hex --force, \
local.rebar --force, \
deps.get, \
compile
RUN echo "" > config/poxa.prod.conf
RUN mix release
RUN mkdir -p /app/$APP_NAME
WORKDIR /app/$APP_NAME
RUN tar xzf /source/_build/prod/rel/$APP_NAME/releases/*/$APP_NAME.tar.gz
# install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
RUN mix deps.get
RUN mix deps.compile

# build project
COPY priv priv
COPY lib lib
RUN mix compile

FROM alpine:3.6
# build release
COPY rel rel
RUN mix release

ENV APP_NAME poxa
ENV MIX_ENV prod
# prepare release image
FROM alpine:3.9 AS app
RUN apk add --update bash openssl

RUN apk --no-cache add bash openssl
RUN mkdir /app
WORKDIR /app

COPY --from=builder /app /app
COPY --from=build /app/_build/prod/rel/poxa ./
RUN chown -R nobody: /app
USER nobody

CMD /app/$APP_NAME/bin/$APP_NAME foreground
ENV HOME=/app
CMD /app/bin/poxa start
66 changes: 40 additions & 26 deletions lib/poxa.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,45 @@ defmodule Poxa do
use Application
require Logger

@registry_adapter Poxa.Registry.adapter
@registry_adapter Poxa.Registry.adapter()

def registry, do: @registry_adapter

def start(_type, _args) do
dispatch = :cowboy_router.compile([
{:_, [ { '/ping', Poxa.PingHandler, [] },
{ '/console', Poxa.Console.WSHandler, [] },
{ '/', :cowboy_static, {:priv_file, :poxa, 'index.html'} },
{ '/static/[...]', :cowboy_static, {:priv_dir, :poxa, 'static'} },
{ '/apps/:app_id/events', Poxa.EventHandler, [] },
{ '/apps/:app_id/channels[/:channel_name]', Poxa.ChannelsHandler, [] },
{ '/apps/:app_id/channels/:channel_name/users', Poxa.UsersHandler, [] },
{ '/app/:app_key', Poxa.WebsocketHandler, [] } ] }
])
dispatch =
:cowboy_router.compile([
{:_,
[
{"/ping", Poxa.PingHandler, []},
{"/console", Poxa.Console.WSHandler, []},
{"/", :cowboy_static, {:priv_file, :poxa, 'index.html'}},
{"/static/[...]", :cowboy_static, {:priv_dir, :poxa, 'static'}},
{"/apps/:app_id/events", Poxa.EventHandler, []},
{"/apps/:app_id/channels[/:channel_name]", Poxa.ChannelsHandler, []},
{"/apps/:app_id/channels/:channel_name/users", Poxa.UsersHandler, []},
{"/app/:app_key", Poxa.WebsocketHandler, []}
]}
])

case load_config() do
{:ok, config} ->
Logger.info "Starting Poxa, app_id: #{config.app_id} on port #{config.port}"
{:ok, _} = :cowboy.start_http(:poxa, 100,
[port: config.port],
[env: [dispatch: dispatch]])
Logger.info("Starting Poxa, app_id: #{config.app_id} on port #{config.port}")

{:ok, _} =
:cowboy.start_clear(:poxa_http, [port: config.port], %{env: %{dispatch: dispatch}})

run_ssl(dispatch)
Poxa.Supervisor.start_link
Poxa.Supervisor.start_link()

:invalid_configuration ->
Logger.error "Error on start, set app_key, app_id and app_secret"
Logger.error("Error on start, set app_key, app_id and app_secret")
exit(:invalid_configuration)
end

end

def stop(_State) do
:ok = :cowboy.stop_listener(:poxa)
:ok = :cowboy.stop_listener(:poxa_http)
:ok = :cowboy.stop_listener(:poxa_https)
end

defp load_config do
Expand All @@ -47,9 +54,15 @@ defmodule Poxa do
{:ok, app_secret} = Application.fetch_env(:poxa, :app_secret)
{:ok, port} = Application.fetch_env(:poxa, :port)
{:ok, registry_adapter} = Application.fetch_env(:poxa, :registry_adapter)
{:ok, %{app_key: app_key, app_id: app_id,
app_secret: app_secret, port: to_integer(port),
registry_adapter: registry_adapter}}

{:ok,
%{
app_key: app_key,
app_id: app_id,
app_secret: app_secret,
port: to_integer(port),
registry_adapter: registry_adapter
}}
rescue
MatchError -> :invalid_configuration
end
Expand All @@ -63,14 +76,15 @@ defmodule Poxa do
{:ok, ssl_config} ->
if enabled_ssl?(ssl_config) do
ssl_port = Keyword.get(ssl_config, :port)
Logger.info "Starting Poxa using SSL on port #{ssl_port}"
Logger.info("Starting Poxa using SSL on port #{ssl_port}")
ssl_config = Keyword.drop(ssl_config, [:enabled])
{:ok, _} = :cowboy.start_https(:https, 100, ssl_config, [env: [dispatch: dispatch] ])
{:ok, _} = :cowboy.start_tls(:poxa_https, ssl_config, %{env: %{dispatch: dispatch}})
else
Logger.info "SSL not configured/started"
Logger.info("SSL not configured/started")
end

:error ->
Logger.info "SSL not configured/started"
Logger.info("SSL not configured/started")
end
end

Expand Down
15 changes: 11 additions & 4 deletions lib/poxa/adapter/gproc.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,34 @@ defmodule Poxa.Adapter.GProc do
end

def subscription_count(channel, pid \\ :_)

def subscription_count(channel, pid) when is_pid(pid) or pid == :_ do
Ex2ms.fun do
{{:p, :l, {:pusher, ^channel}}, ^pid, _} -> true
end |> select_count
end
|> select_count
end

def subscription_count(channel, user_id) do
Ex2ms.fun do
{{:p, :l, {:pusher, ^channel}}, _, {^user_id, _}} -> true
end |> select_count
end
|> select_count
end

def subscriptions(pid) do
Ex2ms.fun do
{{:p, :l, {:pusher, channel}}, ^pid, {user_id, _}} -> [channel, user_id]
end |> select
end
|> select
end

def channels(pid \\ :_) do
Ex2ms.fun do
{{:p, :l, {:pusher, channel}}, ^pid, _} -> channel
end |> select |> Enum.uniq_by(&(&1))
end
|> select
|> Enum.uniq_by(& &1)
end

def unique_subscriptions(channel) do
Expand Down
4 changes: 3 additions & 1 deletion lib/poxa/auth_signature.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ defmodule Poxa.AuthSignature do
[app_key, remote_signed_data] ->
signed_data = sign_data(to_sign)
Poxa.Authentication.check_key(app_key) and signed_data == remote_signed_data
_ -> false

_ ->
false
end
end

Expand Down
4 changes: 3 additions & 1 deletion lib/poxa/authentication.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ defmodule Poxa.Authentication do
{:ok, app_key} = Application.fetch_env(:poxa, :app_key)
{:ok, secret} = Application.fetch_env(:poxa, :app_secret)

valid_body?(body, body_md5) and Signaturex.validate(app_key, secret, method, path, qs_vals, 600)
valid_body?(body, body_md5) and
Signaturex.validate(app_key, secret, method, path, qs_vals, 600)
end

@doc """
Expand All @@ -27,6 +28,7 @@ defmodule Poxa.Authentication do
end

defp valid_body?("", nil), do: true

defp valid_body?(body, body_md5) do
body_md5 == Poxa.CryptoHelper.md5_to_string(body)
end
Expand Down
12 changes: 7 additions & 5 deletions lib/poxa/authorization_helper.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
defmodule Poxa.AuthorizationHelper do
alias Poxa.Authentication

@spec is_authorized(:cowboy_req.req, any) :: {true, :cowboy_req.req, any} | {{false, binary}, :cowboy_req.req, nil}
@spec is_authorized(:cowboy_req.req(), any) ::
{true, :cowboy_req.req(), any} | {{false, binary}, :cowboy_req.req(), nil}
def is_authorized(req, state) do
{:ok, body, req} = :cowboy_req.body(req)
{method, req} = :cowboy_req.method(req)
{qs_vals, req} = :cowboy_req.qs_vals(req)
{path, req} = :cowboy_req.path(req)
{:ok, body, req} = :cowboy_req.read_body(req)
method = :cowboy_req.method(req)
qs_vals = :cowboy_req.parse_qs(req)
path = :cowboy_req.path(req)

if Authentication.check(method, path, body, qs_vals) do
{true, req, state}
else
Expand Down
12 changes: 7 additions & 5 deletions lib/poxa/channel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ defmodule Poxa.Channel do
"""
def matches?(_, nil), do: false
def matches?(_, ""), do: false

def matches?(channel, prefix) do
base = byte_size(prefix)

case channel do
<<^prefix :: binary-size(base), _ :: binary>> -> true
<<^prefix::binary-size(base), _::binary>> -> true
_ -> false
end
end
Expand All @@ -95,19 +97,19 @@ defmodule Poxa.Channel do
Returns the list of channels the `pid` is subscribed
"""
@spec all(pid | :_) :: [binary]
def all(pid \\ :_), do: Poxa.registry.channels(pid)
def all(pid \\ :_), do: Poxa.registry().channels(pid)

@doc """
Returns a boolean indicating if the user identified by `identifier` is subscribed to the channel.
"""
@spec member?(binary, pid | :_ | PresenceSubscription.user_id) :: boolean
@spec member?(binary, pid | :_ | PresenceSubscription.user_id()) :: boolean
def member?(channel, identifier \\ :_), do: subscription_count(channel, identifier) != 0

@doc """
Returns how many connections are opened on the `channel`
"""
@spec subscription_count(binary, pid | :_ | PresenceSubscription.user_id) :: non_neg_integer
@spec subscription_count(binary, pid | :_ | PresenceSubscription.user_id()) :: non_neg_integer
def subscription_count(channel, pid \\ :_) do
Poxa.registry.subscription_count(channel, pid)
Poxa.registry().subscription_count(channel, pid)
end
end
Loading