Current section

Files

Jump to
glimit src glimit@registry.erl
Raw

src/glimit@registry.erl

-module(glimit@registry).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glimit/registry.gleam").
-export([get_or_create/2, get_all/1, remove/2, sweep/1, new/2]).
-export_type([state/1, message/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-type state(FQR) :: {state,
fun((FQR) -> integer()),
fun((FQR) -> integer()),
gleam@dict:dict(FQR, gleam@erlang@process:subject(glimit@rate_limiter:message())),
gleam@option:option(integer()),
gleam@erlang@process:subject(message(FQR))}.
-type message(FQS) :: {get_or_create,
FQS,
gleam@erlang@process:subject({ok,
gleam@erlang@process:subject(glimit@rate_limiter:message())} |
{error, nil})} |
{get_all,
gleam@erlang@process:subject(list({FQS,
gleam@erlang@process:subject(glimit@rate_limiter:message())}))} |
{remove, FQS, gleam@erlang@process:subject(nil)} |
sweep |
{sweep_sync, gleam@erlang@process:subject(nil)} |
{sweep_batch,
list({FQS, gleam@erlang@process:subject(glimit@rate_limiter:message())})}.
-file("src/glimit/registry.gleam", 68).
?DOC(false).
-spec handle_get_or_create(FQX, state(FQX)) -> {ok,
gleam@erlang@process:subject(glimit@rate_limiter:message())} |
{error, nil}.
handle_get_or_create(Identifier, State) ->
case begin
_pipe = erlang:element(4, State),
gleam_stdlib:map_get(_pipe, Identifier)
end of
{ok, Existing} ->
Is_alive = case gleam@erlang@process:subject_owner(Existing) of
{ok, Pid} ->
erlang:is_process_alive(Pid);
{error, _} ->
false
end,
case Is_alive of
true ->
{ok, Existing};
false ->
gleam@result:'try'(
glimit@rate_limiter:new(
(erlang:element(2, State))(Identifier),
(erlang:element(3, State))(Identifier)
),
fun(Rl) -> {ok, Rl} end
)
end;
{error, _} ->
gleam@result:'try'(
glimit@rate_limiter:new(
(erlang:element(2, State))(Identifier),
(erlang:element(3, State))(Identifier)
),
fun(Rate_limiter) -> {ok, Rate_limiter} end
)
end.
-file("src/glimit/registry.gleam", 128).
?DOC(false).
-spec schedule_sweep(state(any())) -> nil.
schedule_sweep(State) ->
case erlang:element(5, State) of
{some, Ms} ->
_ = gleam@erlang@process:send_after(
erlang:element(6, State),
Ms,
sweep
),
nil;
none ->
nil
end.
-file("src/glimit/registry.gleam", 241).
?DOC(false).
-spec get_or_create(gleam@erlang@process:subject(message(FRU)), FRU) -> {ok,
gleam@erlang@process:subject(glimit@rate_limiter:message())} |
{error, nil}.
get_or_create(Registry, Identifier) ->
_pipe = glimit@utils:safe_call(
Registry,
fun(_capture) -> {get_or_create, Identifier, _capture} end,
1000
),
gleam@result:flatten(_pipe).
-file("src/glimit/registry.gleam", 251).
?DOC(false).
-spec get_all(gleam@erlang@process:subject(message(FRZ))) -> list({FRZ,
gleam@erlang@process:subject(glimit@rate_limiter:message())}).
get_all(Registry) ->
_pipe = glimit@utils:safe_call(
Registry,
fun(Field@0) -> {get_all, Field@0} end,
1000
),
gleam@result:unwrap(_pipe, []).
-file("src/glimit/registry.gleam", 260).
?DOC(false).
-spec remove(gleam@erlang@process:subject(message(FSD)), FSD) -> {ok, nil} |
{error, nil}.
remove(Registry, Identifier) ->
glimit@utils:safe_call(
Registry,
fun(_capture) -> {remove, Identifier, _capture} end,
1000
).
-file("src/glimit/registry.gleam", 270).
?DOC(false).
-spec sweep(gleam@erlang@process:subject(message(any()))) -> {ok, nil} |
{error, nil}.
sweep(Registry) ->
glimit@utils:safe_call(
Registry,
fun(Field@0) -> {sweep_sync, Field@0} end,
1000
).
-file("src/glimit/registry.gleam", 103).
?DOC(false).
-spec do_sweep(
list({FRC, gleam@erlang@process:subject(glimit@rate_limiter:message())}),
state(FRC)
) -> state(FRC).
do_sweep(Entries, State) ->
{To_remove, _} = begin
_pipe = Entries,
gleam@list:partition(
_pipe,
fun(Pair) ->
{_, Rl} = Pair,
_pipe@1 = glimit@utils:safe_call(
Rl,
fun(Field@0) -> {has_full_bucket, Field@0} end,
10
),
gleam@result:unwrap(_pipe@1, true)
end
)
end,
gleam@list:each(
To_remove,
fun(Pair@1) ->
{_, Rl@1} = Pair@1,
glimit@rate_limiter:shutdown(Rl@1)
end
),
Registry = begin
_pipe@2 = erlang:element(4, State),
gleam@dict:drop(
_pipe@2,
gleam@list:map(
To_remove,
fun(Pair@2) -> erlang:element(1, Pair@2) end
)
)
end,
{state,
erlang:element(2, State),
erlang:element(3, State),
Registry,
erlang:element(5, State),
erlang:element(6, State)}.
-file("src/glimit/registry.gleam", 138).
?DOC(false).
-spec handle_message(state(FRJ), message(FRJ)) -> gleam@otp@actor:next(state(FRJ), message(FRJ)).
handle_message(State, Message) ->
case Message of
{get_or_create, Identifier, Client} ->
case handle_get_or_create(Identifier, State) of
{ok, Rate_limiter} ->
Registry = begin
_pipe = erlang:element(4, State),
gleam@dict:insert(_pipe, Identifier, Rate_limiter)
end,
State@1 = {state,
erlang:element(2, State),
erlang:element(3, State),
Registry,
erlang:element(5, State),
erlang:element(6, State)},
gleam@otp@actor:send(Client, {ok, Rate_limiter}),
gleam@otp@actor:continue(State@1);
{error, _} ->
gleam@otp@actor:send(Client, {error, nil}),
gleam@otp@actor:continue(State)
end;
{get_all, Client@1} ->
Rate_limiters = begin
_pipe@1 = erlang:element(4, State),
maps:to_list(_pipe@1)
end,
gleam@otp@actor:send(Client@1, Rate_limiters),
gleam@otp@actor:continue(State);
{remove, Identifier@1, Client@2} ->
case begin
_pipe@2 = erlang:element(4, State),
gleam_stdlib:map_get(_pipe@2, Identifier@1)
end of
{ok, Rl} ->
glimit@rate_limiter:shutdown(Rl);
{error, _} ->
nil
end,
Registry@1 = begin
_pipe@3 = erlang:element(4, State),
gleam@dict:delete(_pipe@3, Identifier@1)
end,
State@2 = {state,
erlang:element(2, State),
erlang:element(3, State),
Registry@1,
erlang:element(5, State),
erlang:element(6, State)},
gleam@otp@actor:send(Client@2, nil),
gleam@otp@actor:continue(State@2);
sweep ->
Entries = begin
_pipe@4 = erlang:element(4, State),
maps:to_list(_pipe@4)
end,
gleam@otp@actor:send(
erlang:element(6, State),
{sweep_batch, Entries}
),
gleam@otp@actor:continue(State);
{sweep_sync, Client@3} ->
Entries@1 = begin
_pipe@5 = erlang:element(4, State),
maps:to_list(_pipe@5)
end,
State@3 = do_sweep(Entries@1, State),
gleam@otp@actor:send(Client@3, nil),
gleam@otp@actor:continue(State@3);
{sweep_batch, Entries@2} ->
{Batch, Remaining} = gleam@list:split(Entries@2, 50),
State@4 = do_sweep(Batch, State),
case Remaining of
[] ->
schedule_sweep(State@4),
gleam@otp@actor:continue(State@4);
_ ->
gleam@otp@actor:send(
erlang:element(6, State@4),
{sweep_batch, Remaining}
),
gleam@otp@actor:continue(State@4)
end
end.
-file("src/glimit/registry.gleam", 210).
?DOC(false).
-spec new(fun((FRQ) -> integer()), fun((FRQ) -> integer())) -> {ok,
gleam@erlang@process:subject(message(FRQ))} |
{error, nil}.
new(Per_second, Burst_limit) ->
Sweep_interval_ms = {some, 10000},
_pipe@1 = gleam@otp@actor:new_with_initialiser(
1000,
fun(Self_subject) ->
State = {state,
Burst_limit,
Per_second,
maps:new(),
Sweep_interval_ms,
Self_subject},
schedule_sweep(State),
{ok,
begin
_pipe = gleam@otp@actor:initialised(State),
gleam@otp@actor:returning(_pipe, Self_subject)
end}
end
),
_pipe@2 = gleam@otp@actor:on_message(_pipe@1, fun handle_message/2),
_pipe@3 = gleam@otp@actor:start(_pipe@2),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(Started) -> erlang:element(3, Started) end
),
gleam@result:map_error(_pipe@4, fun(_) -> nil end).