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_minute/2, per_hour/2, handler/2, identifier/2, try_build/1, build/1, apply/2, apply2/2, apply3/2, apply4/2]).
-export_type([rate_limiter/3, rate_limiter_builder/3]).
-type rate_limiter(HSK, HSL, HSM) :: {rate_limiter,
gleam@erlang@process:subject(glimit@actor:message(HSM)),
fun((HSK) -> HSL),
fun((HSK) -> HSM)}.
-type rate_limiter_builder(HSN, HSO, HSP) :: {rate_limiter_builder,
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(integer()),
gleam@option:option(fun((HSN) -> HSP)),
gleam@option:option(fun((HSN) -> HSO))}.
-spec new() -> rate_limiter_builder(any(), any(), any()).
new() ->
{rate_limiter_builder, none, none, none, none, none}.
-spec per_second(rate_limiter_builder(HSW, HSX, HSY), integer()) -> rate_limiter_builder(HSW, HSX, HSY).
per_second(Limiter, Limit) ->
erlang:setelement(2, Limiter, {some, Limit}).
-spec per_minute(rate_limiter_builder(HTF, HTG, HTH), integer()) -> rate_limiter_builder(HTF, HTG, HTH).
per_minute(Limiter, Limit) ->
erlang:setelement(3, Limiter, {some, Limit}).
-spec per_hour(rate_limiter_builder(HTO, HTP, HTQ), integer()) -> rate_limiter_builder(HTO, HTP, HTQ).
per_hour(Limiter, Limit) ->
erlang:setelement(4, Limiter, {some, Limit}).
-spec handler(rate_limiter_builder(HTX, HTY, HTZ), fun((HTX) -> HTY)) -> rate_limiter_builder(HTX, HTY, HTZ).
handler(Limiter, Handler) ->
erlang:setelement(6, Limiter, {some, Handler}).
-spec identifier(rate_limiter_builder(HUG, HUH, HUI), fun((HUG) -> HUI)) -> rate_limiter_builder(HUG, HUH, HUI).
identifier(Limiter, Identifier) ->
erlang:setelement(5, Limiter, {some, Identifier}).
-spec try_build(rate_limiter_builder(HUY, HUZ, HVA)) -> {ok,
rate_limiter(HUY, HUZ, HVA)} |
{error, binary()}.
try_build(Config) ->
gleam@result:'try'(
begin
_pipe = glimit@actor:new(
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config)
),
gleam@result:map_error(
_pipe,
fun(_) -> <<"Failed to start rate limiter actor"/utf8>> end
)
end,
fun(Subject) -> gleam@result:'try'(case erlang:element(5, Config) of
{some, Identifier} ->
{ok, Identifier};
none ->
{error, <<"Identifier function is required"/utf8>>}
end, fun(Identifier@1) ->
gleam@result:'try'(case erlang:element(6, Config) of
{some, Handler} ->
{ok, Handler};
none ->
{error, <<"Handler function is required"/utf8>>}
end, fun(Handler@1) ->
{ok,
{rate_limiter, Subject, Handler@1, Identifier@1}}
end)
end) end
).
-spec build(rate_limiter_builder(HUP, HUQ, HUR)) -> rate_limiter(HUP, HUQ, HUR).
build(Config) ->
case try_build(Config) of
{ok, Limiter} ->
Limiter;
{error, Message} ->
erlang:error(#{gleam_error => panic,
message => Message,
module => <<"glimit"/utf8>>,
function => <<"build"/utf8>>,
line => 130})
end.
-spec apply(fun((HVJ) -> HVK), rate_limiter(HVJ, HVK, any())) -> fun((HVJ) -> HVK).
apply(Func, Limiter) ->
fun(Input) ->
Identifier = (erlang:element(4, Limiter))(Input),
case glimit@actor:hit(erlang:element(2, Limiter), Identifier) of
{ok, nil} ->
Func(Input);
{error, nil} ->
(erlang:element(3, Limiter))(Input)
end
end.
-spec apply2(fun((HVP, HVQ) -> HVR), rate_limiter({HVP, HVQ}, HVR, any())) -> fun((HVP, HVQ) -> HVR).
apply2(Func, Limiter) ->
fun(A, B) ->
Identifier = (erlang:element(4, Limiter))({A, B}),
case glimit@actor:hit(erlang:element(2, Limiter), Identifier) of
{ok, nil} ->
Func(A, B);
{error, nil} ->
(erlang:element(3, Limiter))({A, B})
end
end.
-spec apply3(
fun((HVW, HVX, HVY) -> HVZ),
rate_limiter({HVW, HVX, HVY}, HVZ, any())
) -> fun((HVW, HVX, HVY) -> HVZ).
apply3(Func, Limiter) ->
fun(A, B, C) ->
Identifier = (erlang:element(4, Limiter))({A, B, C}),
case glimit@actor:hit(erlang:element(2, Limiter), Identifier) of
{ok, nil} ->
Func(A, B, C);
{error, nil} ->
(erlang:element(3, Limiter))({A, B, C})
end
end.
-spec apply4(
fun((HWE, HWF, HWG, HWH) -> HWI),
rate_limiter({HWE, HWF, HWG, HWH}, HWI, any())
) -> fun((HWE, HWF, HWG, HWH) -> HWI).
apply4(Func, Limiter) ->
fun(A, B, C, D) ->
Identifier = (erlang:element(4, Limiter))({A, B, C, D}),
case glimit@actor:hit(erlang:element(2, Limiter), Identifier) of
{ok, nil} ->
Func(A, B, C, D);
{error, nil} ->
(erlang:element(3, Limiter))({A, B, C, D})
end
end.