Current section
Files
Jump to
Current section
Files
src/glimit.erl
-module(glimit).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/0, per_second/2, per_second_fn/2, burst_limit/2, burst_limit_fn/2, on_limit_exceeded/2, identifier/2, build/1, apply_built/2, apply/2]).
-export_type([rate_limiter/3, rate_limiter_builder/3]).
-type rate_limiter(HVP, HVQ, HVR) :: {rate_limiter,
gleam@erlang@process:subject(glimit@registry:message(HVR)),
fun((HVP) -> HVQ),
fun((HVP) -> HVR)}.
-type rate_limiter_builder(HVS, HVT, HVU) :: {rate_limiter_builder,
gleam@option:option(fun((HVU) -> integer())),
gleam@option:option(fun((HVU) -> integer())),
gleam@option:option(fun((HVS) -> HVU)),
gleam@option:option(fun((HVS) -> HVT))}.
-spec new() -> rate_limiter_builder(any(), any(), any()).
new() ->
{rate_limiter_builder, none, none, none, none}.
-spec per_second(rate_limiter_builder(HWB, HWC, HWD), integer()) -> rate_limiter_builder(HWB, HWC, HWD).
per_second(Limiter, Limit) ->
erlang:setelement(2, Limiter, {some, fun(_) -> Limit end}).
-spec per_second_fn(
rate_limiter_builder(HWK, HWL, HWM),
fun((HWM) -> integer())
) -> rate_limiter_builder(HWK, HWL, HWM).
per_second_fn(Limiter, Limit_fn) ->
erlang:setelement(2, Limiter, {some, Limit_fn}).
-spec burst_limit(rate_limiter_builder(HWT, HWU, HWV), integer()) -> rate_limiter_builder(HWT, HWU, HWV).
burst_limit(Limiter, Burst_limit) ->
erlang:setelement(3, Limiter, {some, fun(_) -> Burst_limit end}).
-spec burst_limit_fn(
rate_limiter_builder(HXC, HXD, HXE),
fun((HXE) -> integer())
) -> rate_limiter_builder(HXC, HXD, HXE).
burst_limit_fn(Limiter, Burst_limit_fn) ->
erlang:setelement(3, Limiter, {some, Burst_limit_fn}).
-spec on_limit_exceeded(rate_limiter_builder(HXL, HXM, HXN), fun((HXL) -> HXM)) -> rate_limiter_builder(HXL, HXM, HXN).
on_limit_exceeded(Limiter, On_limit_exceeded) ->
erlang:setelement(5, Limiter, {some, On_limit_exceeded}).
-spec identifier(rate_limiter_builder(HXU, HXV, HXW), fun((HXU) -> HXW)) -> rate_limiter_builder(HXU, HXV, HXW).
identifier(Limiter, Identifier) ->
erlang:setelement(4, Limiter, {some, Identifier}).
-spec build(rate_limiter_builder(HYD, HYE, HYF)) -> {ok,
rate_limiter(HYD, HYE, HYF)} |
{error, binary()}.
build(Config) ->
gleam@result:'try'(case erlang:element(2, Config) of
{some, Per_second} ->
{ok, Per_second};
none ->
{error, <<"`per_second` rate limit is required"/utf8>>}
end, fun(Per_second@1) ->
Burst_limit@1 = case erlang:element(3, Config) of
{some, Burst_limit} ->
Burst_limit;
none ->
Per_second@1
end,
gleam@result:'try'(
begin
_pipe = glimit@registry:new(Per_second@1, Burst_limit@1),
gleam@result:map_error(
_pipe,
fun(_) ->
<<"Failed to start rate limiter registry"/utf8>>
end
)
end,
fun(Rate_limiter_registry) ->
gleam@result:'try'(case erlang:element(4, Config) of
{some, Identifier} ->
{ok, Identifier};
none ->
{error,
<<"`identifier` function is required"/utf8>>}
end, fun(Identifier@1) ->
gleam@result:'try'(case erlang:element(5, Config) of
{some, On_limit_exceeded} ->
{ok, On_limit_exceeded};
none ->
{error,
<<"`on_limit_exceeded` function is required"/utf8>>}
end, fun(On_limit_exceeded@1) ->
{ok,
{rate_limiter,
Rate_limiter_registry,
On_limit_exceeded@1,
Identifier@1}}
end)
end)
end
)
end).
-spec apply_built(fun((HYU) -> HYV), rate_limiter(HYU, HYV, any())) -> fun((HYU) -> HYV).
apply_built(Func, Limiter) ->
fun(Input) ->
Identifier = (erlang:element(4, Limiter))(Input),
case begin
_pipe = erlang:element(2, Limiter),
glimit@registry:get_or_create(_pipe, Identifier)
end of
{ok, Rate_limiter} ->
case begin
_pipe@1 = Rate_limiter,
glimit@rate_limiter:hit(_pipe@1)
end of
{ok, nil} ->
Func(Input);
{error, nil} ->
(erlang:element(3, Limiter))(Input)
end;
{error, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Failed to get rate limiter"/utf8>>,
module => <<"glimit"/utf8>>,
function => <<"apply_built"/utf8>>,
line => 283})
end
end.
-spec apply(fun((HYO) -> HYP), rate_limiter_builder(HYO, HYP, any())) -> fun((HYO) -> HYP).
apply(Func, Config) ->
Limiter@1 = case build(Config) of
{ok, Limiter} ->
Limiter;
{error, Message} ->
erlang:error(#{gleam_error => panic,
message => Message,
module => <<"glimit"/utf8>>,
function => <<"apply"/utf8>>,
line => 260})
end,
apply_built(Func, Limiter@1).