Packages

Elixir Plug for Ralitobu, the Rate Limiter with Token Bucket algorithm

Current section

Files

Jump to
ralitobu_plug lib ralitobu plug conn.ex
Raw

lib/ralitobu/plug/conn.ex

defmodule Ralitobu.Plug.Conn do
@moduledoc """
Ralitobu.Plug specific connection helper functions
"""
import Plug.Conn
alias Ralitobu.Plug.State
@state_key :ralitobu_plug
def get_state(conn),
do: Dict.get(conn.private, @state_key, %State{})
def get_state_value(conn, key, default \\ nil),
do: Map.get(get_state(conn), key, default)
def put_state(conn, key, value),
do: put_state(conn, [{key, value}])
def put_state(conn, kv_list),
do: put_private(conn, @state_key, struct(get_state(conn), kv_list))
# Why no "x-" prefix? -> http://tools.ietf.org/html/bcp178
def put_ratelimit_headers(conn) do
state = get_state(conn)
conn
|> put_resp_header("ratelimit-limit", to_string(state.limit))
|> put_resp_header("ratelimit-remaining", to_string(state.remaining))
|> put_resp_header("ratelimit-reset", to_string(state.reset))
end
def pass_or_halt(conn),
do: do_pass_or_halt(conn, get_state_value(conn, :success))
defp do_pass_or_halt(conn, nil), do: conn
defp do_pass_or_halt(conn, :ok), do: conn
defp do_pass_or_halt(conn, :error) do
state = get_state(conn)
s_reset = to_string(state.reset)
conn
|> put_resp_header("retry-after", s_reset)
|> put_resp_content_type("application/json")
|> send_resp(429, error_json(s_reset))
|> halt
end
defp error_json(reset_timer) do
"""
~s({"status": 429, "error": "Too Many Requests", "retry_after": #{reset_timer}})
"""
end
# --- not sure about the wording ---
# defp error_json(reset_timer) do
# "{"
# <> ~S("status": 429, )
# <> ~S("error": "Too Many Requests", )
# <> ~s("retry_after": #{reset_timer},\n)
# <> ~S( "message": "Please respect the rate limit and check the HTTP headers)
# <> ~S( to adjust your client's behaviour accordingly.")
# <> "}\n"
# end
end