defmodule KV.Limiter do
@table __MODULE__
def start, do: :ets.new(@table, [:set, :public, :named_table, write_concurrency: true])
def check(client, limit, now) do
slot = {client, div(now, 1_000)}
count = :ets.update_counter(@table, slot, {2, 1}, {slot, 0})
if count <= limit, do: :ok, else: {:error, :rate_limited}
end
# Old windows are useless once the clock has moved
# past them.
def sweep(now) do
current = div(now, 1_000)
:ets.select_delete(@table, [{{{:_, :"$1"}, :_}, [{:<, :"$1", current}], [true]}])
end
end