Current section
Files
Jump to
Current section
Files
src/glimit@actor.erl
-module(glimit@actor).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/3, hit/2, stop/1]).
-export_type([message/1, state/3]).
-type message(HNG) :: shutdown |
{hit, HNG, gleam@erlang@process:subject({ok, nil} | {error, nil})}.
-type state(HNH, HNI, HNJ) :: {rate_limiter_state,
gleam@dict:dict(HNJ, list(integer())),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(integer())} |
{gleam_phantom, HNH, HNI}.
-spec handle_message(message(HNK), state(HNM, HNN, HNK)) -> gleam@otp@actor:next(message(HNK), state(HNM, HNN, HNK)).
handle_message(Message, State) ->
case Message of
shutdown ->
{stop, normal};
{hit, Identifier, Client} ->
Timestamp = glimit@utils:now(),
Hits = begin
_pipe = erlang:element(2, State),
_pipe@1 = gleam@dict:get(_pipe, Identifier),
_pipe@2 = gleam@result:unwrap(_pipe@1, []),
_pipe@3 = gleam@list:filter(
_pipe@2,
fun(Hit) -> Hit >= (Timestamp - (60 * 60)) end
),
lists:append(_pipe@3, [Timestamp])
end,
Hit_log = begin
_pipe@4 = erlang:element(2, State),
gleam@dict:insert(_pipe@4, Identifier, Hits)
end,
State@1 = erlang:setelement(2, State, Hit_log),
Hits_last_hour = begin
_pipe@5 = Hits,
erlang:length(_pipe@5)
end,
Hits_last_minute = begin
_pipe@6 = Hits,
_pipe@7 = gleam@list:filter(
_pipe@6,
fun(Hit@1) -> Hit@1 >= (Timestamp - 60) end
),
erlang:length(_pipe@7)
end,
Hits_last_second = begin
_pipe@8 = Hits,
_pipe@9 = gleam@list:filter(
_pipe@8,
fun(Hit@2) -> Hit@2 >= (Timestamp - 1) end
),
erlang:length(_pipe@9)
end,
Limit_reached = ((case erlang:element(5, State@1) of
{some, Limit} ->
Hits_last_hour > Limit;
none ->
false
end orelse case erlang:element(4, State@1) of
{some, Limit@1} ->
Hits_last_minute > Limit@1;
none ->
false
end) orelse case erlang:element(3, State@1) of
{some, Limit@2} ->
Hits_last_second > Limit@2;
none ->
false
end),
case Limit_reached of
true ->
gleam@erlang@process:send(Client, {error, nil});
false ->
gleam@erlang@process:send(Client, {ok, nil})
end,
gleam@otp@actor:continue(State@1)
end.
-spec new(
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(integer())
) -> {ok, gleam@erlang@process:subject(message(any()))} | {error, nil}.
new(Per_second, Per_minute, Per_hour) ->
State = {rate_limiter_state,
gleam@dict:new(),
Per_second,
Per_minute,
Per_hour},
_pipe = gleam@otp@actor:start(State, fun handle_message/2),
gleam@result:nil_error(_pipe).
-spec hit(gleam@erlang@process:subject(message(HOF)), HOF) -> {ok, nil} |
{error, nil}.
hit(Subject, Identifier) ->
gleam@otp@actor:call(
Subject,
fun(_capture) -> {hit, Identifier, _capture} end,
10
).
-spec stop(gleam@erlang@process:subject(message(any()))) -> nil.
stop(Subject) ->
gleam@otp@actor:send(Subject, shutdown).