emqx_utils_agent.erl 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2024 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %% http://www.apache.org/licenses/LICENSE-2.0
  8. %%
  9. %% Unless required by applicable law or agreed to in writing, software
  10. %% distributed under the License is distributed on an "AS IS" BASIS,
  11. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. %% See the License for the specific language governing permissions and
  13. %% limitations under the License.
  14. %%--------------------------------------------------------------------
  15. %% @doc Similar to Elixir's [`Agent'](https://hexdocs.pm/elixir/Agent.html).
  16. -module(emqx_utils_agent).
  17. %% API
  18. -export([start_link/1, get/1, get_and_update/2]).
  19. %% `gen_server' API
  20. -export([init/1, handle_call/3]).
  21. %%------------------------------------------------------------------------------
  22. %% Type declarations
  23. %%------------------------------------------------------------------------------
  24. -type state() :: term().
  25. -type get_and_update_fn() :: fun((state()) -> {term(), state()}).
  26. -record(get_and_update, {fn :: get_and_update_fn()}).
  27. %%------------------------------------------------------------------------------
  28. %% API
  29. %%------------------------------------------------------------------------------
  30. -spec start_link(state()) -> gen_server:start_ret().
  31. start_link(InitState) ->
  32. gen_server:start_link(?MODULE, InitState, []).
  33. -spec get(gen_server:server_ref()) -> term().
  34. get(ServerRef) ->
  35. Fn = fun(St) -> {St, St} end,
  36. gen_server:call(ServerRef, #get_and_update{fn = Fn}).
  37. -spec get_and_update(gen_server:server_ref(), get_and_update_fn()) -> term().
  38. get_and_update(ServerRef, Fn) ->
  39. gen_server:call(ServerRef, #get_and_update{fn = Fn}).
  40. %%------------------------------------------------------------------------------
  41. %% `gen_server' API
  42. %%------------------------------------------------------------------------------
  43. init(InitState) ->
  44. {ok, InitState}.
  45. handle_call(#get_and_update{fn = Fn}, _From, State0) ->
  46. {Reply, State} = Fn(State0),
  47. {reply, Reply, State}.
  48. %%------------------------------------------------------------------------------
  49. %% Internal fns
  50. %%------------------------------------------------------------------------------