-module(glimiter). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new_limiter/2, limit_guard/4, update/2]). -export_type([limiter/1]). -opaque limiter(HFM) :: {limiter, gleam@dict:dict(HFM, list(birl:time())), integer(), birl@duration:duration()}. -spec new_limiter(integer(), birl@duration:duration()) -> limiter(any()). new_limiter(Count, Size) -> {limiter, gleam@dict:new(), Count, Size}. -spec limit_guard(limiter(HFS), HFS, HFU, fun(() -> HFU)) -> HFU. limit_guard(Limiter, Key, Consequence, Alternetive) -> _assert_subject = gleam@dict:get(erlang:element(2, Limiter), Key), {ok, Times} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glimiter"/utf8>>, function => <<"limit_guard"/utf8>>, line => 27}) end, case erlang:length(Times) < erlang:element(3, Limiter) of true -> Alternetive(); false -> Consequence end. -spec add(limiter(HFV), HFV) -> gleam@dict:dict(HFV, list(birl:time())). add(Limiter, Key) -> Now = birl:now(), case gleam@dict:get(erlang:element(2, Limiter), Key) of {ok, Timestamps} -> gleam@dict:insert( erlang:element(2, Limiter), Key, [Now | Timestamps] ); {error, _} -> gleam@dict:insert(erlang:element(2, Limiter), Key, [Now]) end. -spec filter_prev_window(limiter(HGA), HGA) -> gleam@dict:dict(HGA, list(birl:time())). filter_prev_window(Limiter, Key) -> _assert_subject = gleam@dict:get(erlang:element(2, Limiter), Key), {ok, Times} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glimiter"/utf8>>, function => <<"filter_prev_window"/utf8>>, line => 49}) end, Now = birl:now(), New_times = gleam@list:filter( Times, fun(Time) -> End_time = birl:add(Time, erlang:element(4, Limiter)), case birl:compare(Now, End_time) of lt -> true; eq -> true; _ -> false end end ), gleam@dict:insert(erlang:element(2, Limiter), Key, New_times). -spec update(limiter(HFP), HFP) -> limiter(HFP). update(Limiter, Key) -> Limiter@1 = {limiter, add(Limiter, Key), erlang:element(3, Limiter), erlang:element(4, Limiter)}, {limiter, filter_prev_window(Limiter@1, Key), erlang:element(3, Limiter@1), erlang:element(4, Limiter@1)}.