Skip to content

Commit

Permalink
feat: use new X-RateLimit-Reset-After header with millisecond X-RateL…
Browse files Browse the repository at this point in the history
…imit-Precision
  • Loading branch information
SpaceEEC committed Aug 16, 2019
1 parent 1d96805 commit d8c9c82
Show file tree
Hide file tree
Showing 5 changed files with 8 additions and 79 deletions.
2 changes: 0 additions & 2 deletions lib/rest/functions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ defmodule Crux.Rest.Functions do
message,
&Endpoints.message_reactions(&1, &2, emoji, "@me")
)
# https://github.com/discordapp/discord-api-docs/issues/182
|> Request.set_rate_limit_reset(250)
end

@impl true
Expand Down
40 changes: 0 additions & 40 deletions lib/rest/handler/global.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,6 @@ defmodule Crux.Rest.Handler.Global do
GenServer.start_link(__MODULE__, nil, name: name)
end

@doc """
Fetches the average out of the last ten offsets to discord servers in milliseconds.
"""
@spec fetch_offset(name :: atom()) :: integer()
def fetch_offset(name) do
name
|> Module.concat(Global)
|> GenServer.call(:offset)
end

@doc """
Adds an offset to the list of offsets.
"""
@spec add_offset(name :: atom(), offset :: integer()) :: :ok
def add_offset(_name, nil), do: :ok

def add_offset(name, offset) do
name
|> Module.concat(Global)
|> GenServer.call({:offset, offset})
end

@doc """
Fetches how long to wait until the global rate limit is over.
Is not positive when not rate limited.
Expand Down Expand Up @@ -66,24 +44,6 @@ defmodule Crux.Rest.Handler.Global do

@doc false
@impl true
def handle_call(:offset, _from, {offsets, _reset} = state) when length(offsets) <= 0 do
{:reply, 0, state}
end

def handle_call(:offset, _from, {offsets, _reset} = state) do
offset =
offsets
|> Enum.sum()
|> div(length(offsets))

{:reply, offset, state}
end

def handle_call({:offset, offset}, _from, {offsets, reset}) do
offsets = [offset | Enum.slice(offsets, 0..9)]

{:reply, :ok, {offsets, reset}}
end

def handle_call(:retry, _from, {_offsets, reset} = state) do
{:reply, reset - :os.system_time(:millisecond), state}
Expand Down
35 changes: 7 additions & 28 deletions lib/rest/handler/handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,6 @@ defmodule Crux.Rest.Handler do
|> handle_headers(res)
|> handle_response(res)

# https://github.com/discordapp/discord-api-docs/issues/182
state =
if request.rate_limit_reset do
%{state | reset: request.rate_limit_reset + :os.system_time(:millisecond)}
else
state
end

if is_number(wait) do
Logger.debug("[Crux][Rest][Handler][#{route}]: Waiting #{wait}ms")
:timer.sleep(wait)
Expand All @@ -166,29 +158,20 @@ defmodule Crux.Rest.Handler do

# Apply rate limit and date header
defp handle_headers(
%Handler{name: name} = state,
%Handler{} = state,
{:ok, %HTTPoison.Response{headers: headers}}
) do
date =
headers
|> List.keyfind("Date", 0)
|> parse_header()

Global.add_offset(name, date)

remaining =
headers
|> List.keyfind("X-RateLimit-Remaining", 0)
|> parse_header()

reset =
headers
|> List.keyfind("X-RateLimit-Reset", 0)
|> List.keyfind("X-RateLimit-Reset-After", 0)
|> parse_header()

if remaining && reset do
reset = reset * 1000 - Global.fetch_offset(name)

%{state | remaining: remaining, reset: reset}
else
state
Expand Down Expand Up @@ -249,17 +232,13 @@ defmodule Crux.Rest.Handler do
defp parse_header(nil), do: nil
defp parse_header({"X-RateLimit-Global", _value}), do: true

defp parse_header({"Date", value}) do
case Timex.parse(value, "{WDshort}, {D} {Mshort} {YYYY} {h24}:{m}:{s} {Zabbr}") do
{:ok, date_time} ->
DateTime.to_unix(date_time, :millisecond) - :os.system_time(:millisecond)
defp parse_header({"X-RateLimit-Remaining", value}), do: String.to_integer(value)

{:error, _} ->
nil
end
end
defp parse_header({"X-RateLimit-Reset-After", value}) do

defp parse_header({_name, value}), do: String.to_integer(value)
{value, ""} = Float.parse(value)
trunc(value * 1000) + :os.system_time(:millisecond)
end

defp wait(timeout, route) when timeout > 0 do
Logger.debug("[Crux][Rest][Handler][#{route}]: Rate limited, waiting #{timeout}ms")
Expand Down
1 change: 1 addition & 0 deletions lib/rest/http.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ defmodule Crux.Rest.HTTP do
def process_request_headers(headers) do
headers
|> Keyword.put_new(:"content-type", "application/json")
|> Keyword.put_new(:"X-RateLimit-Precision", "millisecond")
|> Keyword.put_new(:"user-agent", @user_agent)
end

Expand Down
9 changes: 0 additions & 9 deletions lib/rest/request.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ defmodule Crux.Rest.Request do
:route,
:path,
:transform,
:rate_limit_reset,
:params,
data: "",
headers: []
Expand Down Expand Up @@ -91,14 +90,6 @@ defmodule Crux.Rest.Request do
%{t | headers: [{"authorization", "Bot " <> token} | headers]}
end

@doc false
# https://github.com/discordapp/discord-api-docs/issues/182
Version.since("0.2.0")
@spec set_rate_limit_reset(t(), reset :: non_neg_integer() | nil) :: t()
def set_rate_limit_reset(%__MODULE__{} = t, reset) do
%{t | rate_limit_reset: reset}
end

### End Create / Set

### Work
Expand Down

0 comments on commit d8c9c82

Please sign in to comment.