-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).