-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([pid/1, new/2, make_store/1, 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(gleam@option:option(glimit@bucket:bucket_state()))} | {set, binary(), glimit@bucket:bucket_state(), gleam@erlang@process:subject(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", 141). ?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", 130). ?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", 152). ?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", 91). ?DOC(false). -spec handle_message(state(), msg()) -> gleam@otp@actor:next(state(), msg()). handle_message(State, Msg) -> case Msg of {get, Key, Reply} -> gleam@otp@actor:send( Reply, begin _pipe = gleam_stdlib:map_get(erlang:element(2, State), Key), gleam@option:from_result(_pipe) end ), 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, nil), gleam@otp@actor:continue( {state, Data, erlang:element(3, State), erlang:element(4, State), erlang:element(5, State)} ); {sweep, Now, Max_idle_ms, Reply@2} -> Data@1 = do_sweep(erlang:element(2, State), Now, Max_idle_ms), gleam@otp@actor:send(Reply@2, 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@3} -> gleam@otp@actor:send(Reply@3, maps:size(erlang:element(2, State))), gleam@otp@actor:continue(State); {remove, Key@2, Reply@4} -> Data@3 = gleam@dict:delete(erlang:element(2, State), Key@2), gleam@otp@actor:send(Reply@4, 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", 160). ?DOC(false). -spec pid(memory_store()) -> {ok, gleam@erlang@process:pid_()} | {error, nil}. pid(Store) -> gleam@erlang@process:subject_owner(erlang:element(2, Store)). -file("src/glimit/memory_store.gleam", 45). ?DOC(false). -spec new(gleam@option:option(integer()), integer()) -> {ok, 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} -> {ok, {memory_store, erlang:element(3, Started)}}; {error, _} -> {error, nil} end. -file("src/glimit/memory_store.gleam", 79). ?DOC(false). -spec make_store(memory_store()) -> glimit@bucket:store(). make_store(Store) -> {store, fun(Key) -> glimit@utils:safe_call( erlang:element(2, Store), fun(_capture) -> {get, Key, _capture} end, 1000 ) end, fun(Key@1, State, _) -> glimit@utils:safe_call( erlang:element(2, Store), fun(_capture@1) -> {set, Key@1, State, _capture@1} end, 1000 ) end, fun(_) -> {ok, nil} end}. -file("src/glimit/memory_store.gleam", 166). ?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", 173). ?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", 179). ?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 ).