-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, build/1, apply/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 build(rate_limiter_builder(HUP, HUQ, HUR)) -> rate_limiter(HUP, HUQ, HUR). build(Config) -> {rate_limiter, case glimit@actor:new( erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config) ) of {ok, Subject} -> Subject; {error, _} -> erlang:error(#{gleam_error => panic, message => <<"Failed to start rate limiter actor"/utf8>>, module => <<"glimit"/utf8>>, function => <<"build"/utf8>>, line => 132}) end, case erlang:element(6, Config) of {some, Handler} -> Handler; none -> erlang:error(#{gleam_error => panic, message => <<"Handler function is required"/utf8>>, module => <<"glimit"/utf8>>, function => <<"build"/utf8>>, line => 140}) end, case erlang:element(5, Config) of {some, Identifier} -> Identifier; none -> erlang:error(#{gleam_error => panic, message => <<"Identifier function is required"/utf8>>, module => <<"glimit"/utf8>>, function => <<"build"/utf8>>, line => 136}) end}. -spec apply(fun((HUY) -> HUZ), rate_limiter(HUY, HUZ, any())) -> fun((HUY) -> HUZ). 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.