-module(glimit@memory_store). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glimit/memory_store.gleam"). -export([new/2, get_count/1, remove/2, sweep/3]). -export_type([memory_store/0, state/0, msg/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(false). -opaque memory_store() :: {memory_store, gleam@erlang@process:subject(msg())}. -type state() :: {state, gleam@dict:dict(binary(), glimit@bucket:bucket_state()), gleam@option:option(integer()), integer(), gleam@erlang@process:subject(msg())}. -type msg() :: {get, binary(), gleam@erlang@process:subject({ok, gleam@option:option(glimit@bucket:bucket_state())} | {error, nil})} | {set, binary(), glimit@bucket:bucket_state(), integer(), gleam@erlang@process:subject({ok, nil} | {error, nil})} | {lock, binary(), gleam@erlang@process:subject({ok, nil} | {error, nil})} | {unlock, binary(), gleam@erlang@process:subject({ok, nil} | {error, nil})} | {sweep, integer(), gleam@option:option(integer()), gleam@erlang@process:subject(nil)} | sweep_timer | {get_count, gleam@erlang@process:subject(integer())} | {remove, binary(), gleam@erlang@process:subject(nil)}. -file("src/glimit/memory_store.gleam", 175). ?DOC(false). -spec is_idle( glimit@bucket:bucket_state(), integer(), gleam@option:option(integer()) ) -> boolean(). is_idle(B, Now, Max_idle_ms) -> case Max_idle_ms of none -> false; {some, Threshold} -> case erlang:element(5, B) of none -> true; {some, Last_update} -> (Now - Last_update) > Threshold end end. -file("src/glimit/memory_store.gleam", 164). ?DOC(false). -spec do_sweep( gleam@dict:dict(binary(), glimit@bucket:bucket_state()), integer(), gleam@option:option(integer()) ) -> gleam@dict:dict(binary(), glimit@bucket:bucket_state()). do_sweep(Data, Now, Max_idle_ms) -> _pipe = Data, gleam@dict:filter( _pipe, fun(_, B) -> not glimit@bucket:is_full(B, Now) andalso not is_idle( B, Now, Max_idle_ms ) end ). -file("src/glimit/memory_store.gleam", 186). ?DOC(false). -spec schedule_sweep(state()) -> nil. schedule_sweep(State) -> _ = gleam@erlang@process:send_after( erlang:element(5, State), erlang:element(4, State), sweep_timer ), nil. -file("src/glimit/memory_store.gleam", 111). ?DOC(false). -spec handle_message(state(), msg()) -> gleam@otp@actor:next(state(), msg()). handle_message(State, Msg) -> case Msg of {get, Key, Reply} -> Result = case gleam_stdlib:map_get(erlang:element(2, State), Key) of {ok, B} -> {ok, {some, B}}; {error, _} -> {ok, none} end, gleam@otp@actor:send(Reply, Result), gleam@otp@actor:continue(State); {set, Key@1, Bucket_state, _, Reply@1} -> Data = gleam@dict:insert( erlang:element(2, State), Key@1, Bucket_state ), gleam@otp@actor:send(Reply@1, {ok, nil}), gleam@otp@actor:continue( {state, Data, erlang:element(3, State), erlang:element(4, State), erlang:element(5, State)} ); {lock, _, Reply@2} -> gleam@otp@actor:send(Reply@2, {ok, nil}), gleam@otp@actor:continue(State); {unlock, _, Reply@3} -> gleam@otp@actor:send(Reply@3, {ok, nil}), gleam@otp@actor:continue(State); {sweep, Now, Max_idle_ms, Reply@4} -> Data@1 = do_sweep(erlang:element(2, State), Now, Max_idle_ms), gleam@otp@actor:send(Reply@4, nil), gleam@otp@actor:continue( {state, Data@1, erlang:element(3, State), erlang:element(4, State), erlang:element(5, State)} ); sweep_timer -> Now@1 = glimit@utils:now(), Data@2 = do_sweep( erlang:element(2, State), Now@1, erlang:element(3, State) ), schedule_sweep(State), gleam@otp@actor:continue( {state, Data@2, erlang:element(3, State), erlang:element(4, State), erlang:element(5, State)} ); {get_count, Reply@5} -> gleam@otp@actor:send(Reply@5, maps:size(erlang:element(2, State))), gleam@otp@actor:continue(State); {remove, Key@2, Reply@6} -> Data@3 = gleam@dict:delete(erlang:element(2, State), Key@2), gleam@otp@actor:send(Reply@6, nil), gleam@otp@actor:continue( {state, Data@3, erlang:element(3, State), erlang:element(4, State), erlang:element(5, State)} ) end. -file("src/glimit/memory_store.gleam", 90). ?DOC(false). -spec make_store(gleam@erlang@process:subject(msg())) -> glimit@bucket:store(). make_store(Subject) -> {store, fun(Key) -> _pipe = glimit@utils:safe_call( Subject, fun(_capture) -> {get, Key, _capture} end, 1000 ), gleam@result:flatten(_pipe) end, fun(Key@1, State, Ttl) -> _pipe@1 = glimit@utils:safe_call( Subject, fun(_capture@1) -> {set, Key@1, State, Ttl, _capture@1} end, 1000 ), gleam@result:flatten(_pipe@1) end, fun(_) -> {ok, nil} end, fun(_) -> {ok, nil} end}. -file("src/glimit/memory_store.gleam", 55). ?DOC(false). -spec new(gleam@option:option(integer()), integer()) -> {ok, {glimit@bucket:store(), memory_store()}} | {error, nil}. new(Max_idle_ms, Sweep_interval_ms) -> Start_result = begin _pipe@1 = gleam@otp@actor:new_with_initialiser( 1000, fun(Self_subject) -> State = {state, maps:new(), Max_idle_ms, Sweep_interval_ms, Self_subject}, schedule_sweep(State), {ok, begin _pipe = gleam@otp@actor:initialised(State), gleam@otp@actor:returning(_pipe, Self_subject) end} end ), _pipe@2 = gleam@otp@actor:on_message(_pipe@1, fun handle_message/2), gleam@otp@actor:start(_pipe@2) end, case Start_result of {ok, Started} -> Subject = erlang:element(3, Started), Store = make_store(Subject), Handle = {memory_store, Subject}, {ok, {Store, Handle}}; {error, _} -> {error, nil} end. -file("src/glimit/memory_store.gleam", 194). ?DOC(false). -spec get_count(memory_store()) -> integer(). get_count(Store) -> _pipe = glimit@utils:safe_call( erlang:element(2, Store), fun(Field@0) -> {get_count, Field@0} end, 1000 ), gleam@result:unwrap(_pipe, 0). -file("src/glimit/memory_store.gleam", 201). ?DOC(false). -spec remove(memory_store(), binary()) -> {ok, nil} | {error, nil}. remove(Store, Key) -> glimit@utils:safe_call( erlang:element(2, Store), fun(_capture) -> {remove, Key, _capture} end, 1000 ). -file("src/glimit/memory_store.gleam", 207). ?DOC(false). -spec sweep(memory_store(), integer(), gleam@option:option(integer())) -> {ok, nil} | {error, nil}. sweep(Store, Now, Max_idle_ms) -> glimit@utils:safe_call( erlang:element(2, Store), fun(_capture) -> {sweep, Now, Max_idle_ms, _capture} end, 1000 ).